1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sourceforge.domian.specification;
17
18
19 import java.math.BigDecimal;
20 import java.math.BigInteger;
21 import java.util.Calendar;
22 import java.util.Date;
23 import java.util.Iterator;
24
25 import org.apache.commons.lang.Validate;
26
27 import static java.lang.Boolean.FALSE;
28 import static java.lang.Boolean.TRUE;
29 import static net.sourceforge.domian.util.ReflectionUtils.canCastAtLeastOneWay;
30 import static net.sourceforge.domian.util.ReflectionUtils.isDate;
31
32
33 abstract class AbstractComparableValueBoundSpecification<T extends Comparable> extends AbstractValueBoundSpecification<T> {
34
35 private static long MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
36
37
38 AbstractComparableValueBoundSpecification(final T value) {
39 super(value);
40 }
41
42
43 @Override
44 protected Boolean isInvertible() {
45 return TRUE;
46 }
47
48
49 @Override
50 protected Specification<T> invert() {
51 return createValueBoundSpecification(getBinaryRelation(TRUE), this.value);
52 }
53
54
55
56
57
58
59
60 @SuppressWarnings("unchecked")
61 protected Long getCompareValue(final T candidateOperandValue) {
62 if (candidateOperandValue instanceof Number && this.value instanceof Number) {
63 final BigDecimal thisBigDecimal = new BigDecimal(this.value.toString());
64 final BigDecimal candidateBigDecimal = new BigDecimal(candidateOperandValue.toString());
65 final BigDecimal subtractedValue = candidateBigDecimal.subtract(thisBigDecimal);
66 BigInteger subtractedBigInteger;
67 try {
68 subtractedBigInteger = subtractedValue.toBigIntegerExact();
69 } catch (ArithmeticException e) {
70 subtractedBigInteger = subtractedValue.unscaledValue();
71 }
72 return subtractedBigInteger.longValue();
73
74 } else if (isDate(candidateOperandValue) && isDate(this.value)) {
75 if (isMidnight((Date) this.value) && isMidnight((Date) candidateOperandValue)) {
76 return getDayNumberInEra((Date) candidateOperandValue) - getDayNumberInEra((Date) this.value);
77 } else {
78 return ((Date) candidateOperandValue).getTime() - ((Date) this.value).getTime();
79 }
80
81 } else if (candidateOperandValue instanceof Comparable) {
82 return (long) candidateOperandValue.compareTo(this.value);
83
84 } else {
85 return null;
86 }
87 }
88
89
90 private static boolean isMidnight(Date date) {
91 Calendar calendar = Calendar.getInstance();
92 calendar.setTime(date);
93
94 final int dateHour = calendar.get(Calendar.HOUR);
95 final int dateMinute = calendar.get(Calendar.MINUTE);
96 final int dateSecond = calendar.get(Calendar.SECOND);
97 final int dateMillisecond = calendar.get(Calendar.MILLISECOND);
98
99 if (dateHour == 0
100 && dateMinute == 0
101 && dateSecond == 0
102 && dateMillisecond == 0) {
103 return true;
104 }
105 return false;
106 }
107
108
109 private static long getDayNumberInEra(Date date) {
110 return date.getTime() / MILLISECONDS_PER_DAY;
111 }
112
113
114 @Override
115 @SuppressWarnings("unchecked")
116 public Boolean isDisjointWith(final Specification<?> specification) {
117 Validate.notNull(specification, "Specification parameter cannot be null");
118
119
120 if (this == specification || this.equals(specification)) {
121 return FALSE;
122 }
123
124
125 if (!canCastAtLeastOneWay(this.getType(), specification.getType())) {
126 return TRUE;
127 }
128
129 if (specification instanceof ValueBoundSpecification) {
130 final AbstractValueBoundSpecification valueBoundSpecificationCandidate = (AbstractValueBoundSpecification) specification;
131
132
133 return getDisjointDecision(valueBoundSpecificationCandidate.getBinaryRelation(),
134 (T) valueBoundSpecificationCandidate.getValue());
135 }
136
137 if (specification instanceof JointDenialSpecification) {
138
139 Specification purifiedSpec = ((AbstractSpecification) specification).purify(true);
140 if (purifiedSpec instanceof JointDenialSpecification) {
141 Specification<?> negatedSpec = getNegatedSpecification((JointDenialSpecification<?>) purifiedSpec);
142 if (negatedSpec instanceof ValueBoundSpecification) {
143 final AbstractValueBoundSpecification negatedValueBoundSpecification = (AbstractValueBoundSpecification) negatedSpec;
144 if (isOddNumber(getNumberOfLevelsOfNegations((JointDenialSpecification) purifiedSpec, 0))) {
145 negatedSpec = negatedValueBoundSpecification.invert();
146 } else {
147 negatedSpec = negatedValueBoundSpecification;
148 }
149
150 if (negatedSpec instanceof DisjunctionSpecification) {
151 final AbstractCompositeSpecification compositeSpecification = (AbstractCompositeSpecification) negatedSpec;
152 final Iterator<Specification<?>> iterator = compositeSpecification.specifications.iterator();
153 if (compositeSpecification instanceof DisjunctionSpecification) {
154 for (; iterator.hasNext();) {
155 final Specification<?> spec = iterator.next();
156 if (canCastAtLeastOneWay(spec.getType(), this.getType())) {
157 if (!this.isDisjointWith(spec)) {
158 return FALSE;
159 }
160 }
161 }
162 return TRUE;
163
164 } else {
165 return TRUE;
166 }
167 }
168
169
170
171 return getDisjointDecision(((AbstractValueBoundSpecification) negatedSpec).getBinaryRelation(),
172 (T) ((AbstractValueBoundSpecification) negatedSpec).getValue());
173
174
175 } else if (negatedSpec instanceof DisjunctionSpecification) {
176 final Specification resolvedSpecification;
177 if (isOddNumber(getNumberOfLevelsOfNegations((JointDenialSpecification) specification, 0)) &&
178 ((AbstractSpecification) specification).isInvertible()) {
179 resolvedSpecification = ((DisjunctionSpecification) negatedSpec).invert();
180 } else {
181 resolvedSpecification = negatedSpec;
182 }
183
184 if (resolvedSpecification instanceof ValueBoundSpecification) {
185 return resolvedSpecification.isDisjointWith(this);
186 }
187
188
189 for (final Object composite : ((AbstractCompositeSpecification) resolvedSpecification).specifications) {
190 if (!this.isDisjointWith((Specification<?>) composite)) {
191 return FALSE;
192 }
193 }
194 return TRUE;
195 }
196 } else {
197
198 return this.isDisjointWith(purifiedSpec);
199 }
200 }
201
202 if (specification instanceof DisjunctionSpecification) {
203 for (final Object composite : ((AbstractCompositeSpecification) specification).specifications) {
204 if (!((Specification<?>) composite).isDisjointWith(this)) {
205 return FALSE;
206 }
207 }
208 return TRUE;
209 }
210
211 if (specification instanceof CompositeSpecification) {
212 for (final Object composite : ((AbstractCompositeSpecification) specification).specifications) {
213 if (!this.isDisjointWith((Specification<?>) composite)) {
214 return FALSE;
215 }
216 }
217 return TRUE;
218 }
219
220 return TRUE;
221 }
222 }