001 package org.apache.commons.contract.constraints; 002 003 import java.math.BigDecimal; 004 import java.util.ArrayList; 005 import java.util.Arrays; 006 import java.util.Iterator; 007 import java.util.List; 008 009 import org.apache.commons.contract.Context; 010 import org.apache.commons.i18n.bundles.ErrorBundle; 011 import org.apache.commons.i18n.bundles.TextBundle; 012 013 public class NumberConstraints implements Constraints { 014 public final static NumberConstraints UNCONSTRAINED = new NumberConstraints(); 015 public final static NumberConstraints POSITIVE = new NumberConstraints(new Integer(0), null, false); 016 public final static NumberConstraints NEGATIVE = new NumberConstraints(null, new Integer(0), false); 017 018 protected boolean constrained, inclusive; 019 protected List allowedValues = new ArrayList(); 020 protected Number minimum, maximum; 021 022 public NumberConstraints() { 023 this.constrained = false; 024 } 025 026 public NumberConstraints(Number minimum, Number maximum) { 027 this(minimum, maximum, true); 028 } 029 030 public NumberConstraints(Number minimum, Number maximum, boolean inclusive) { 031 constrained = true; 032 this.minimum = minimum; 033 this.maximum = maximum; 034 this.inclusive = inclusive; 035 } 036 037 public NumberConstraints(Number[] allowedValues) { 038 this.constrained = true; 039 this.allowedValues = new ArrayList(Arrays.asList(allowedValues)); 040 } 041 042 public boolean isConstrained() { 043 return constrained; 044 } 045 046 public void addAllowedValue(Number value) { 047 allowedValues.add(value); 048 } 049 050 public Number[] getAllowedValues() { 051 if ( allowedValues.isEmpty() ) return null; 052 return (Number [])allowedValues.toArray(new Number[0]); 053 } 054 055 public void setMinimum(Number minimum) { 056 constrained = true; 057 this.minimum = minimum; 058 } 059 060 public Number getMinimum() { 061 return minimum; 062 } 063 064 public void setMaximum(Number maximum) { 065 constrained = true; 066 this.maximum = maximum; 067 } 068 069 public Number getMaximum() { 070 return maximum; 071 } 072 073 public Object cast(Object value, Context context) throws CastException { 074 if ( value instanceof Number) { 075 return (Number)value; 076 } else { 077 try { 078 return new BigDecimal(StringConstraints.UNCONSTRAINED.cast(value, null).toString()); 079 } catch ( NumberFormatException exception ) { 080 throw new CastException(new ErrorBundle("uncastableNumber", new Object[] { value }), exception); 081 } catch ( CastException exception ) { 082 throw new CastException(new ErrorBundle("uncastableNumber", new Object[] { value }), exception); 083 } 084 } 085 } 086 087 public void validate(Object value, Context context) throws ValidationException { 088 if ( constrained ) { 089 Number number = (Number)value; 090 if ( getAllowedValues() != null ) { 091 for ( Iterator i = allowedValues.iterator(); i.hasNext(); ) { 092 Number allowedNumber = (Number)i.next(); 093 if ( allowedNumber.equals(number) ) { 094 return; 095 } 096 } 097 throw new ValidationException(new ErrorBundle("invalidNumber", new Object[] { value })); 098 } else { 099 if ( inclusive && minimum != null && minimum.doubleValue() > number.doubleValue() ) { 100 throw new ValidationException(new ErrorBundle("numberMustBeGreater", new Object[] { number, minimum })); 101 } 102 if ( !inclusive && minimum != null && minimum.doubleValue() >= number.doubleValue() ) { 103 throw new ValidationException(new ErrorBundle("numberMustBeGreaterOrEqual", new Object[] { number, minimum })); 104 } 105 if ( inclusive && maximum != null && maximum.doubleValue() < number.doubleValue() ) { 106 throw new ValidationException(new ErrorBundle("numberMustBeLess", new Object[] { number, minimum })); 107 } 108 if ( !inclusive && maximum != null && maximum.doubleValue() >= number.doubleValue() ) { 109 throw new ValidationException(new ErrorBundle("numberMustBeLessOrEqual", new Object[] { number, minimum })); 110 } 111 } 112 } 113 } 114 115 public TextBundle verboseConstraints() { 116 if ( constrained ) { 117 if ( inclusive && maximum != null && minimum == null ) { 118 return new TextBundle("lessOrEqual", new Object[] { maximum } ); 119 } else if ( !inclusive && maximum != null && minimum == null ) { 120 return new TextBundle("less", new Object[] { maximum } ); 121 } else if ( inclusive && minimum != null && maximum == null ) { 122 return new TextBundle("greaterOrEqual", new Object[] { minimum } ); 123 } else if ( !inclusive && minimum != null && maximum == null ) { 124 return new TextBundle("greater", new Object[] { minimum } ); 125 } else if ( inclusive && maximum != null && minimum != null ) { 126 return new TextBundle("rangeIncluding", new Object[] { minimum, maximum } ); 127 } else { 128 return new TextBundle("rangeExcluding", new Object[] { minimum, maximum } ); 129 } 130 } else { 131 return new TextBundle("numbers"); 132 } 133 } 134 }