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.util.HashSet;
20 import java.util.Map;
21 import java.util.Set;
22
23 import org.apache.commons.lang.Validate;
24
25 import static java.lang.Boolean.FALSE;
26 import static java.lang.Boolean.TRUE;
27 import static net.sourceforge.domian.util.ReflectionUtils.canCast;
28 import static net.sourceforge.domian.util.ReflectionUtils.canCastAtLeastOneWay;
29 import static net.sourceforge.domian.util.ReflectionUtils.canCastFrom_To;
30
31
32
33
34
35
36
37
38
39
40
41 final class DisjunctionSpecification<T> extends AbstractCompositeSpecification<T> {
42
43 DisjunctionSpecification(final Class<T> type) {
44 super(type);
45 }
46
47
48 @Override
49 public Boolean isSatisfiedBy(final T candidate) {
50 if (candidate == null) {
51 return FALSE;
52 }
53 if (this.type == null && this.specifications.isEmpty()) {
54 return TRUE;
55 }
56 if (this.type != null && canCastFrom_To(candidate.getClass(), this.type) && this.specifications.isEmpty()) {
57 return TRUE;
58 }
59 for (final Specification<? super T> specification : this.specifications) {
60 if (specification == null || specification.isSatisfiedBy(candidate)) {
61 return TRUE;
62 }
63 }
64 return FALSE;
65 }
66
67
68 @Override
69 public Boolean isDisjointWith(final Specification<?> specification) {
70 Validate.notNull(specification, "Specification parameter cannot be null");
71
72
73 if (this == specification || this.equals(specification)) {
74 return FALSE;
75 }
76
77
78 if (!canCastAtLeastOneWay(this.getType(), specification.getType())) {
79 return TRUE;
80 }
81
82
83 if (this.isSpecifyingAllInstancesOfItsType()) {
84 if (specification instanceof JointDenialSpecification) {
85 final Specification<?> negatedSpec = getNegatedSpecification((JointDenialSpecification<T>) specification);
86 if (negatedSpec.equals(this)) {
87 return TRUE;
88 }
89 }
90 return FALSE;
91 }
92
93 if (specification instanceof ValueBoundSpecification) {
94 for (final Specification<?> spec : this.specifications) {
95 if (!spec.isDisjointWith(specification)) {
96 return FALSE;
97 }
98 }
99 return TRUE;
100 }
101
102 if (specification instanceof JointDenialSpecification) {
103
104 final JointDenialSpecification jointDenialSpecification = (JointDenialSpecification) specification;
105 final Specification negatedSpec = getNegatedSpecification(jointDenialSpecification);
106 if (canCast(this.getType(), negatedSpec.getType()) && jointDenialSpecification.isTypeExcludingSpecification()) {
107 return TRUE;
108 }
109
110 return specification.isDisjointWith(this);
111 }
112
113 if (specification instanceof DisjunctionSpecification) {
114 if (this.hasParameterization()) {
115 final AbstractCompositeSpecification candidateConjuntionSpecification = (AbstractCompositeSpecification) specification;
116 if (candidateConjuntionSpecification.hasParameterization()) {
117 final Map<String, Set<LeafSpecification>> leafSpecificationMap = this.getLeafSpecificationMap();
118 final Map<String, Set<LeafSpecification>> candidateLeafSpecificationMap = candidateConjuntionSpecification.getLeafSpecificationMap();
119 for (final String memberName : leafSpecificationMap.keySet()) {
120 if (candidateLeafSpecificationMap.keySet().contains(memberName)) {
121 final Set<LeafSpecification> specificationSet = leafSpecificationMap.get(memberName);
122 final Set<LeafSpecification> memberSpecificationSet = candidateLeafSpecificationMap.get(memberName);
123 for (final Specification leafSpecification : specificationSet) {
124 for (final Specification memberLeafSpecification : memberSpecificationSet) {
125 if (!leafSpecification.isDisjointWith(memberLeafSpecification)) {
126 return FALSE;
127 }
128 }
129 }
130 } else {
131 return FALSE;
132 }
133 }
134 for (final String memberName : candidateLeafSpecificationMap.keySet()) {
135 if (leafSpecificationMap.keySet().contains(memberName)) {
136 final Set<LeafSpecification> specificationSet = leafSpecificationMap.get(memberName);
137 final Set<LeafSpecification> memberSpecificationSet = candidateLeafSpecificationMap.get(memberName);
138 for (final Specification leafSpecification : memberSpecificationSet) {
139 for (final Specification memberLeafSpecification : specificationSet) {
140 if (!leafSpecification.isDisjointWith(memberLeafSpecification)) {
141 return FALSE;
142 }
143 }
144 }
145 } else {
146 return FALSE;
147 }
148 }
149 return TRUE;
150 }
151
152 } else {
153
154 final AbstractCompositeSpecification<?> compositeSpecification = (AbstractCompositeSpecification) specification;
155 for (final Specification spec : compositeSpecification.specifications) {
156 if (!spec.isDisjointWith(this)) {
157 return FALSE;
158 }
159 }
160 return TRUE;
161 }
162 }
163
164 if (specification instanceof ConjunctionSpecification) {
165 final AbstractCompositeSpecification<?> conjunctionCandidate = (AbstractCompositeSpecification) specification;
166 if (conjunctionCandidate.isSimpleComposition()) {
167
168 final Set<Specification<?>> listOfDisjointDisjunctionSpecs = new HashSet<Specification<?>>();
169 for (final Specification wrappedSpec : conjunctionCandidate.specifications) {
170 for (final Specification spec : this.specifications) {
171 if (wrappedSpec.isDisjointWith(spec)) {
172 listOfDisjointDisjunctionSpecs.add(spec);
173 }
174 }
175 }
176 return listOfDisjointDisjunctionSpecs.equals(this.specifications);
177 }
178
179
180
181 final Set<Specification> commonDisjointToSpecSet = new HashSet<Specification>();
182 for (final Specification wrappedSpec : conjunctionCandidate.specifications) {
183 final Set<Specification> wrappedSpecDisjointToSpecSet = new HashSet<Specification>();
184 for (final Specification spec : this.specifications) {
185 if (wrappedSpec.isDisjointWith(spec)) {
186 wrappedSpecDisjointToSpecSet.add(spec);
187 }
188 }
189 if (wrappedSpecDisjointToSpecSet.isEmpty()) {
190 return FALSE;
191 }
192 if (commonDisjointToSpecSet.isEmpty()) {
193 commonDisjointToSpecSet.addAll(commonDisjointToSpecSet);
194 } else {
195 commonDisjointToSpecSet.retainAll(wrappedSpecDisjointToSpecSet);
196 }
197 }
198 return !commonDisjointToSpecSet.isEmpty();
199 }
200
201 return FALSE;
202 }
203
204
205 @Override
206 protected Boolean isSpecifyingAllInstancesOfItsType() {
207 for (final Specification<? super T> wrappedSpec : this.specifications) {
208 if (wrappedSpec instanceof AbstractCompositeSpecification) {
209 if (((AbstractCompositeSpecification) wrappedSpec).isSpecifyingAllInstancesOfItsType()) {
210 return TRUE;
211 }
212 }
213 }
214 return FALSE;
215 }
216
217
218 @Override
219 protected AbstractSpecification<T> purify(final boolean doPurifyInversions) {
220
221 if (this.specifications.isEmpty()) {
222 return this;
223 }
224
225 if (this.specifications.size() == 1) {
226 return (((AbstractSpecification<T>) this.specifications.iterator().next()).purify(true));
227 }
228
229 final DisjunctionSpecification<T> newPurifiedDisjunctionSpecification = new DisjunctionSpecification<T>(this.getType());
230
231 for (final Specification<? super T> wrappedSpec : this.specifications) {
232
233
234
235 newPurifiedDisjunctionSpecification.specifications.add(((AbstractSpecification<? super T>) wrappedSpec).purify(true));
236
237 }
238 return newPurifiedDisjunctionSpecification;
239 }
240
241
242 @Override
243 protected Boolean isInvertible() {
244
245
246
247
248
249
250
251
252
253
254 if (containsValueBoundSpecificationsOnly(this)) {
255 return TRUE;
256 }
257 return FALSE;
258 }
259
260
261 @Override
262 protected Specification<T> invert() {
263
264
265
266
267
268 if (containsValueBoundSpecificationsOnly(this)) {
269 final Set<Specification<?>> specificationSet = this.getAllSpecifications();
270 Object value = null;
271 boolean hasEqualSpecification = false;
272 boolean hasLessThanSpecification = false;
273 boolean hasGreaterThanSpecification = false;
274 for (Specification specification : specificationSet) {
275 if (specification == this) {
276 continue;
277 }
278 if (specification instanceof EqualSpecification) {
279 hasEqualSpecification = true;
280 if (value == null) {
281 value = ((EqualSpecification) specification).getValue();
282 } else {
283 if (!value.equals(((EqualSpecification) specification).getValue())) {
284
285 return doBooleanAlgebraInversion();
286 } else {
287 if (hasGreaterThanSpecification) {
288 return AbstractSpecification.createValueBoundSpecification(RelationalOperator.LESS_THAN, value);
289 } else if (hasLessThanSpecification) {
290 return AbstractSpecification.createValueBoundSpecification(RelationalOperator.GREATER_THAN, value);
291 }
292
293 }
294 }
295 } else if (specification instanceof GreaterThanSpecification) {
296 hasGreaterThanSpecification = true;
297 if (value == null) {
298 value = ((GreaterThanSpecification) specification).getValue();
299 } else {
300 if (!value.equals(((GreaterThanSpecification) specification).getValue())) {
301
302 return doBooleanAlgebraInversion();
303 } else {
304 if (hasEqualSpecification) {
305 return AbstractSpecification.createValueBoundSpecification(RelationalOperator.LESS_THAN, value);
306 }
307 }
308 }
309 } else if (specification instanceof LessThanSpecification) {
310 hasLessThanSpecification = true;
311 if (value == null) {
312 value = ((LessThanSpecification) specification).getValue();
313 } else {
314 if (!value.equals(((LessThanSpecification) specification).getValue())) {
315
316 return doBooleanAlgebraInversion();
317 } else {
318 if (hasEqualSpecification) {
319 return AbstractSpecification.createValueBoundSpecification(RelationalOperator.GREATER_THAN, value);
320 }
321 }
322 }
323 }
324 }
325 }
326 throw new IllegalStateException("This specification cannot be inverted");
327 }
328
329
330 private Specification<T> doBooleanAlgebraInversion() {
331 final ConjunctionSpecification<T> conjunctionSpecification = new ConjunctionSpecification<T>(getType());
332 for (final Specification<?> specification : this.getAllSpecifications()) {
333 conjunctionSpecification.specifications.add(((AbstractSpecification<? super T>) specification).invert());
334 }
335 return conjunctionSpecification;
336 }
337 }