1 | |
package org.apache.commons.contract.constraints; |
2 | |
|
3 | |
import java.math.BigDecimal; |
4 | |
import java.util.ArrayList; |
5 | |
import java.util.Arrays; |
6 | |
import java.util.Iterator; |
7 | |
import java.util.List; |
8 | |
|
9 | |
import org.apache.commons.contract.Context; |
10 | |
import org.apache.commons.i18n.bundles.ErrorBundle; |
11 | |
import org.apache.commons.i18n.bundles.TextBundle; |
12 | |
|
13 | |
public class NumberConstraints implements Constraints { |
14 | 0 | public final static NumberConstraints UNCONSTRAINED = new NumberConstraints(); |
15 | 0 | public final static NumberConstraints POSITIVE = new NumberConstraints(new Integer(0), null, false); |
16 | 0 | public final static NumberConstraints NEGATIVE = new NumberConstraints(null, new Integer(0), false); |
17 | |
|
18 | |
protected boolean constrained, inclusive; |
19 | 0 | protected List allowedValues = new ArrayList(); |
20 | |
protected Number minimum, maximum; |
21 | |
|
22 | 0 | public NumberConstraints() { |
23 | 0 | this.constrained = false; |
24 | 0 | } |
25 | |
|
26 | |
public NumberConstraints(Number minimum, Number maximum) { |
27 | 0 | this(minimum, maximum, true); |
28 | 0 | } |
29 | |
|
30 | 0 | public NumberConstraints(Number minimum, Number maximum, boolean inclusive) { |
31 | 0 | constrained = true; |
32 | 0 | this.minimum = minimum; |
33 | 0 | this.maximum = maximum; |
34 | 0 | this.inclusive = inclusive; |
35 | 0 | } |
36 | |
|
37 | 0 | public NumberConstraints(Number[] allowedValues) { |
38 | 0 | this.constrained = true; |
39 | 0 | this.allowedValues = new ArrayList(Arrays.asList(allowedValues)); |
40 | 0 | } |
41 | |
|
42 | |
public boolean isConstrained() { |
43 | 0 | return constrained; |
44 | |
} |
45 | |
|
46 | |
public void addAllowedValue(Number value) { |
47 | 0 | allowedValues.add(value); |
48 | 0 | } |
49 | |
|
50 | |
public Number[] getAllowedValues() { |
51 | 0 | if ( allowedValues.isEmpty() ) return null; |
52 | 0 | return (Number [])allowedValues.toArray(new Number[0]); |
53 | |
} |
54 | |
|
55 | |
public void setMinimum(Number minimum) { |
56 | 0 | constrained = true; |
57 | 0 | this.minimum = minimum; |
58 | 0 | } |
59 | |
|
60 | |
public Number getMinimum() { |
61 | 0 | return minimum; |
62 | |
} |
63 | |
|
64 | |
public void setMaximum(Number maximum) { |
65 | 0 | constrained = true; |
66 | 0 | this.maximum = maximum; |
67 | 0 | } |
68 | |
|
69 | |
public Number getMaximum() { |
70 | 0 | return maximum; |
71 | |
} |
72 | |
|
73 | |
public Object cast(Object value, Context context) throws CastException { |
74 | 0 | if ( value instanceof Number) { |
75 | 0 | return (Number)value; |
76 | |
} else { |
77 | |
try { |
78 | 0 | return new BigDecimal(StringConstraints.UNCONSTRAINED.cast(value, null).toString()); |
79 | 0 | } catch ( NumberFormatException exception ) { |
80 | 0 | throw new CastException(new ErrorBundle("uncastableNumber", new Object[] { value }), exception); |
81 | 0 | } catch ( CastException exception ) { |
82 | 0 | throw new CastException(new ErrorBundle("uncastableNumber", new Object[] { value }), exception); |
83 | |
} |
84 | |
} |
85 | |
} |
86 | |
|
87 | |
public void validate(Object value, Context context) throws ValidationException { |
88 | 0 | if ( constrained ) { |
89 | 0 | Number number = (Number)value; |
90 | 0 | if ( getAllowedValues() != null ) { |
91 | 0 | for ( Iterator i = allowedValues.iterator(); i.hasNext(); ) { |
92 | 0 | Number allowedNumber = (Number)i.next(); |
93 | 0 | if ( allowedNumber.equals(number) ) { |
94 | 0 | return; |
95 | |
} |
96 | 0 | } |
97 | 0 | throw new ValidationException(new ErrorBundle("invalidNumber", new Object[] { value })); |
98 | |
} else { |
99 | 0 | if ( inclusive && minimum != null && minimum.doubleValue() > number.doubleValue() ) { |
100 | 0 | throw new ValidationException(new ErrorBundle("numberMustBeGreater", new Object[] { number, minimum })); |
101 | |
} |
102 | 0 | if ( !inclusive && minimum != null && minimum.doubleValue() >= number.doubleValue() ) { |
103 | 0 | throw new ValidationException(new ErrorBundle("numberMustBeGreaterOrEqual", new Object[] { number, minimum })); |
104 | |
} |
105 | 0 | if ( inclusive && maximum != null && maximum.doubleValue() < number.doubleValue() ) { |
106 | 0 | throw new ValidationException(new ErrorBundle("numberMustBeLess", new Object[] { number, minimum })); |
107 | |
} |
108 | 0 | if ( !inclusive && maximum != null && maximum.doubleValue() >= number.doubleValue() ) { |
109 | 0 | throw new ValidationException(new ErrorBundle("numberMustBeLessOrEqual", new Object[] { number, minimum })); |
110 | |
} |
111 | |
} |
112 | |
} |
113 | 0 | } |
114 | |
|
115 | |
public TextBundle verboseConstraints() { |
116 | 0 | if ( constrained ) { |
117 | 0 | if ( inclusive && maximum != null && minimum == null ) { |
118 | 0 | return new TextBundle("lessOrEqual", new Object[] { maximum } ); |
119 | 0 | } else if ( !inclusive && maximum != null && minimum == null ) { |
120 | 0 | return new TextBundle("less", new Object[] { maximum } ); |
121 | 0 | } else if ( inclusive && minimum != null && maximum == null ) { |
122 | 0 | return new TextBundle("greaterOrEqual", new Object[] { minimum } ); |
123 | 0 | } else if ( !inclusive && minimum != null && maximum == null ) { |
124 | 0 | return new TextBundle("greater", new Object[] { minimum } ); |
125 | 0 | } else if ( inclusive && maximum != null && minimum != null ) { |
126 | 0 | return new TextBundle("rangeIncluding", new Object[] { minimum, maximum } ); |
127 | |
} else { |
128 | 0 | return new TextBundle("rangeExcluding", new Object[] { minimum, maximum } ); |
129 | |
} |
130 | |
} else { |
131 | 0 | return new TextBundle("numbers"); |
132 | |
} |
133 | |
} |
134 | |
} |