View Javadoc

1   /*
2    * Copyright 2006-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sourceforge.domian.specification;
17  
18  
19  import java.util.Collections;
20  import java.util.Map;
21  import java.util.Set;
22  
23  import org.apache.commons.lang.NotImplementedException;
24  import org.apache.commons.lang.Validate;
25  
26  import static java.lang.Boolean.FALSE;
27  import static java.lang.Boolean.TRUE;
28  import static net.sourceforge.domian.util.ReflectionUtils.canCast;
29  
30  
31  /**
32   * A joint denial specification where <i>none</i> of the wrapped specifications
33   * must be satisfied for this overall composite specification to be satisfied.
34   * <p/>
35   * The boolean logic operator equivalent is <i><b>NOR</b></i>.
36   *
37   * @author Eirik Torske
38   * @since 0.2
39   */
40  final class JointDenialSpecification<T> extends AbstractCompositeSpecification<T> {
41  
42      JointDenialSpecification(final Class<T> type) {
43          super(type);
44      }
45  
46      @Override
47      protected Boolean isSpecifyingAllInstancesOfItsType() {
48          return FALSE;
49      }
50  
51      /** @return <code>true</code> if this <code>NOR</code> specification excludes all possibilities for satisfaction of candidate objects having this specification's type */
52      Boolean isTypeExcludingSpecification() {
53          for (final Specification<? super T> wrappedSpec : this.specifications) {
54              if (wrappedSpec instanceof CompositeSpecification) {
55                  if (((AbstractCompositeSpecification) wrappedSpec).isSpecifyingAllInstancesOfItsType()) {
56                      return TRUE;
57                  }
58              }
59          }
60          return FALSE;
61      }
62  
63      @Override
64      public Boolean isSatisfiedBy(final T candidate) {
65          if (super.isSatisfiedBy(candidate)) {
66              for (final Specification<? super T> specification : this.specifications) {
67                  if (specification.isSatisfiedBy(candidate)) {
68                      return FALSE;
69                  }
70              }
71              return TRUE;
72          }
73          return FALSE;
74      }
75  
76  
77      @Override
78      public Boolean isDisjointWith(final Specification<?> specification) {
79          Validate.notNull(specification, "Specification parameter cannot be null");
80  
81          // Pruning: if same/equal specifications:
82          if (this == specification || this.equals(specification)) {
83              return FALSE;
84          }
85  
86          Specification<?> negatedThis = null;
87          //negatedThis = getNegatedSpecification(this);
88  
89          // Pruning: if type-only spec - and candidate is negated type-only-spec
90          /* TODO: include or not? less code vs. faster code...?
91          if (this.isSpecifyingAllInstancesOfItsType()) {
92              if (specification instanceof JointDenialSpecification) {
93                  negatedThis = getNegatedSpecification((JointDenialSpecification<T>) specification);
94                  if (negatedThis.equals(this)) {
95                      return TRUE;
96                  }
97              }
98              return FALSE;
99          }
100         */
101 
102         // Extraordinary JointDenialSpecification purification - may result in another CompositeSpecification type
103         AbstractSpecification<T> purifiedThis = this.purify(true);
104         if (purifiedThis != this) {
105             if (purifiedThis instanceof JointDenialSpecification) {
106                 negatedThis = getNegatedSpecification((JointDenialSpecification<T>) purifiedThis);
107             } else {
108                 return purifiedThis.isDisjointWith(specification);
109             }
110         } else {
111             negatedThis = getNegatedSpecification(this);
112         }
113 
114         // Pruning: if specifications and types are fundamentally disjoint
115         try {
116             if (canCast(this.getType(), negatedThis.getType()) && this.isTypeExcludingSpecification()) {
117                 return TRUE;
118             }
119 
120             // TODO: should have be sortened out ASAP...
121         } catch (NotImplementedException e) {
122             // Deliberately left empty (CollectionSpecification trouble)
123         }
124 
125         // Pruning: if type-only spec - and candidate is negated type-only-spec
126         /* TODO: include or not? less code vs. faster code...?
127         if (negatedThis instanceof ConjunctionSpecification &&
128             ((ConjunctionSpecification) negatedThis).isSpecifyingAllInstancesOfItsType()) {
129             if (specification instanceof ConjunctionSpecification &&
130                 ((ConjunctionSpecification) specification).isSpecifyingAllInstancesOfItsType()) {
131                 //if (negatedThis.getType().equals(specification.getType())) {
132                     return TRUE;
133                 //}
134             }
135         }
136         */
137 
138         final int numberOfLevelsOfInversions = getNumberOfLevelsOfNegations(this, 0);
139 
140         if (negatedThis instanceof ValueBoundSpecification) {
141 
142             if (negatedThis instanceof AbstractComparableValueBoundSpecification) {
143                 final AbstractComparableValueBoundSpecification negatedValueBoundSpecification = (AbstractComparableValueBoundSpecification) negatedThis;
144                 final Specification resolvedSpecification;
145                 if (isOddNumber(numberOfLevelsOfInversions)) {
146                     resolvedSpecification = negatedValueBoundSpecification.invert();
147                 } else {
148                     resolvedSpecification = negatedValueBoundSpecification;
149                 }
150 
151                 if (specification instanceof ValueBoundSpecification) {
152                     if (resolvedSpecification instanceof DisjunctionSpecification) {
153                         final AbstractCompositeSpecification<?> compositeSpecification = (AbstractCompositeSpecification) resolvedSpecification;
154                         for (final Specification spec : compositeSpecification.specifications) {
155                             if (!specification.isDisjointWith(spec)) {
156                                 return FALSE;
157                             }
158                         }
159                         return TRUE;
160 
161                     } else if (resolvedSpecification instanceof ValueBoundSpecification) {
162                         return resolvedSpecification.isDisjointWith(specification);
163                     }
164 
165                 } else if (specification instanceof JointDenialSpecification) {
166                     return specification.isDisjointWith(resolvedSpecification);
167 
168                 } else {
169                     return resolvedSpecification.isDisjointWith(specification);
170                 }
171 
172             } else {
173                 if (isOddNumber(numberOfLevelsOfInversions)) {
174                     if (specification instanceof DisjunctionSpecification) {
175                         return FALSE;
176                     }
177                     return !negatedThis.isDisjointWith(specification);
178 
179                 } else {
180                     return negatedThis.isDisjointWith(specification);
181                 }
182             }
183 
184         } else if (negatedThis instanceof DisjunctionSpecification) {
185 
186             if (((DisjunctionSpecification) negatedThis).hasParameterization()) {
187 
188                 final AbstractCompositeSpecification candidateConjuntionSpecification = (AbstractCompositeSpecification) specification;
189                 if (candidateConjuntionSpecification.hasParameterization()) {
190                     final Map<String, Set<LeafSpecification>> leafSpecificationMap = this.getLeafSpecificationMap();
191                     final Map<String, Set<LeafSpecification>> candidateLeafSpecificationMap = candidateConjuntionSpecification.getLeafSpecificationMap();
192                     for (final String memberName : leafSpecificationMap.keySet()) {
193                         if (candidateLeafSpecificationMap.keySet().contains(memberName)) {
194                             final Set<LeafSpecification> specificationSet = leafSpecificationMap.get(memberName);
195                             final Set<LeafSpecification> memberSpecificationSet = candidateLeafSpecificationMap.get(memberName);
196                             for (final Specification leafSpecification : specificationSet) {
197                                 for (final Specification memberLeafSpecification : memberSpecificationSet) {
198                                     if (!leafSpecification.isDisjointWith(memberLeafSpecification)) {
199                                         return FALSE;
200                                     }
201                                 }
202                             }
203                         } else {
204                             if (specification instanceof DisjunctionSpecification) {
205                                 return FALSE;
206                             } else {
207                                 return TRUE;
208                             }
209                         }
210                     }
211                     for (final String memberName : candidateLeafSpecificationMap.keySet()) {
212                         if (leafSpecificationMap.keySet().contains(memberName)) {
213                             final Set<LeafSpecification> specificationSet = leafSpecificationMap.get(memberName);
214                             final Set<LeafSpecification> memberSpecificationSet = candidateLeafSpecificationMap.get(memberName);
215                             for (final Specification leafSpecification : memberSpecificationSet) {
216                                 for (final Specification memberLeafSpecification : specificationSet) {
217                                     if (!leafSpecification.isDisjointWith(memberLeafSpecification)) {
218                                         return FALSE;
219                                     }
220                                 }
221                             }
222                         } else {
223                             if (specification instanceof DisjunctionSpecification) {
224                                 return FALSE;
225                             } else {
226                                 return TRUE;
227                             }
228                         }
229                     }
230                     if (specification instanceof DisjunctionSpecification) {
231                         return TRUE;
232                     } else {
233                         return FALSE;
234                     }
235                 }
236 
237                 // Simple value composite spec
238                 // if one of combinations is NOT disjoint => return false else true
239                 for (Specification<?> spec : this.specifications) {
240                     if (!spec.isDisjointWith(specification)) {
241                         return FALSE;
242                     }
243                 }
244                 return TRUE;
245             }
246 
247             Specification resolvedSpecification;
248 
249             // Composition of ValueBoundSpecifications or other CompositeSpecifications
250             if (isOddNumber(numberOfLevelsOfInversions)) {
251                 if (((DisjunctionSpecification) negatedThis).isInvertible()) {
252                     resolvedSpecification = ((DisjunctionSpecification) negatedThis).invert();
253                     if (resolvedSpecification instanceof ValueBoundSpecification) {
254                         return resolvedSpecification.isDisjointWith(specification);
255                     } else {
256                         return !resolvedSpecification.isDisjointWith(specification);
257                     }
258                 } else {
259                     // TODO: ...
260                     throw new NotImplementedException();
261                 }
262 
263             } else {
264                 resolvedSpecification = negatedThis;
265             }
266 
267             // Composite, JointDenial composites, or Leaf spec...
268             if (resolvedSpecification instanceof JointDenialSpecification) {
269                 throw new NotImplementedException();
270             }
271 
272             if (resolvedSpecification instanceof CompositeSpecification) {
273                 // If one of combinations is NOT disjoint => return false else true
274                 final AbstractCompositeSpecification<?> compositeSpecification = (AbstractCompositeSpecification) resolvedSpecification;
275                 for (final Specification spec : compositeSpecification.specifications) {
276                     if (!resolvedSpecification.isDisjointWith(spec)) {
277                         return FALSE;
278                     }
279                 }
280                 return TRUE;
281             }
282 
283             // TODO: leaf...
284             throw new NotImplementedException();
285 
286 
287         } else if (negatedThis instanceof ConjunctionSpecification) {
288 
289             if (((ConjunctionSpecification) negatedThis).hasParameterization()) {
290                 final AbstractCompositeSpecification candidateConjuntionSpecification = (AbstractCompositeSpecification) specification;
291                 if (candidateConjuntionSpecification.hasParameterization()) {
292                     final Map<String, Set<LeafSpecification>> leafSpecificationMap = this.getLeafSpecificationMap();
293                     final Map<String, Set<LeafSpecification>> candidateLeafSpecificationMap = candidateConjuntionSpecification.getLeafSpecificationMap();
294                     for (final String memberName : leafSpecificationMap.keySet()) {
295                         if (candidateLeafSpecificationMap.keySet().contains(memberName)) {
296                             final Set<LeafSpecification> specificationSet = leafSpecificationMap.get(memberName);
297                             final Set<LeafSpecification> memberSpecificationSet = candidateLeafSpecificationMap.get(memberName);
298                             for (final Specification leafSpecification : specificationSet) {
299                                 for (final Specification memberLeafSpecification : memberSpecificationSet) {
300                                     if (!leafSpecification.isDisjointWith(memberLeafSpecification)) {
301                                         return FALSE;
302                                     }
303                                 }
304                             }
305                         } else {
306                             if (specification instanceof DisjunctionSpecification) {
307                                 return FALSE;
308                             } else {
309                                 if (isOddNumber(numberOfLevelsOfInversions)) {
310                                     return FALSE;
311                                 } else {
312                                     return TRUE;
313                                 }
314 
315                             }
316                         }
317                     }
318                     for (final String memberName : candidateLeafSpecificationMap.keySet()) {
319                         if (leafSpecificationMap.keySet().contains(memberName)) {
320                             final Set<LeafSpecification> specificationSet = leafSpecificationMap.get(memberName);
321                             final Set<LeafSpecification> memberSpecificationSet = candidateLeafSpecificationMap.get(memberName);
322                             for (final Specification leafSpecification : memberSpecificationSet) {
323                                 for (final Specification memberLeafSpecification : specificationSet) {
324                                     if (!leafSpecification.isDisjointWith(memberLeafSpecification)) {
325                                         return FALSE;
326                                     }
327                                 }
328                             }
329                         } else {
330                             if (specification instanceof DisjunctionSpecification) {
331                                 return FALSE;
332                             } else {
333                                 return TRUE;
334                             }
335                         }
336                     }
337                     if (specification instanceof DisjunctionSpecification) {
338                         return TRUE;
339                     } else {
340                         return FALSE;
341                     }
342                 }
343 
344                 // Simple value composite spec
345                 // if one of combinations is NOT disjoint => return false else true
346                 for (Specification<?> spec : this.specifications) {
347                     if (!spec.isDisjointWith(specification)) {
348                         return FALSE;
349                     }
350                 }
351                 return TRUE;
352             }
353 
354 
355             Specification resolvedSpecification;
356 
357             // Composition of ValueBoundSpecifications or other CompositeSpecifications
358             if (isOddNumber(numberOfLevelsOfInversions)) {
359                 return negatedThis.isDisjointWith(specification);
360 
361             } else {
362                 resolvedSpecification = negatedThis;
363             }
364 
365 
366             if (specification instanceof JointDenialSpecification) {
367                 final JointDenialSpecification jointDenialCandidateSpecification = (JointDenialSpecification) specification;
368                 final Specification negatedCandidateSpec = getNegatedSpecification(jointDenialCandidateSpecification);
369                 return negatedCandidateSpec.isDisjointWith(negatedThis);
370             }
371 
372             // Composite, JointDenial composites, or Leaf spec...
373             if (resolvedSpecification instanceof JointDenialSpecification) {
374 
375                 // TODO: ...
376                 throw new NotImplementedException();
377             }
378 
379             if (resolvedSpecification instanceof CompositeSpecification) {
380                 // If one of combinations is NOT disjoint => return false else true
381                 final AbstractCompositeSpecification<?> compositeSpecification = (AbstractCompositeSpecification) resolvedSpecification;
382                 for (final Specification spec : compositeSpecification.specifications) {
383                     if (!resolvedSpecification.isDisjointWith(spec)) {
384                         return FALSE;
385                     }
386                 }
387                 return TRUE;
388             }
389 
390             // TODO: ...
391             throw new NotImplementedException();
392 
393 
394         } else {
395             if (isOddNumber(numberOfLevelsOfInversions)) {
396                 return !negatedThis.isDisjointWith(specification);
397             } else {
398                 return negatedThis.isDisjointWith(specification);
399             }
400         }
401         throw new NotImplementedException();
402     }
403 
404 
405     @Override
406     protected AbstractSpecification<T> purify(final boolean doPurifyInversions) {
407         //setPurified(true);
408         final Specification<T> negatedSpec = getNegatedSpecification(this);
409         final int numberOfLevelsOfInversions = getNumberOfLevelsOfNegations(this, 0);
410         if (negatedSpec instanceof AbstractValueBoundSpecification) {
411             if (doPurifyInversions) {
412                 if (isOddNumber(numberOfLevelsOfInversions)) {
413                     if (((AbstractValueBoundSpecification<T>) negatedSpec).isInvertible()) {
414                         return ((AbstractSpecification<T>) ((AbstractValueBoundSpecification<T>) negatedSpec).invert()).purify(true);
415                     } else {
416                         return purifyWithoutAnyInversionOfWrappedSpecs();
417                     }
418                 } else {
419                     return ((AbstractSpecification<T>) negatedSpec).purify(true);
420                 }
421             }
422             return purifyWithoutAnyInversionOfWrappedSpecs();
423 
424         } else if (negatedSpec instanceof DisjunctionSpecification) {
425             if (doPurifyInversions) {
426                 if (isOddNumber(numberOfLevelsOfInversions)) {
427                     if (((DisjunctionSpecification<T>) negatedSpec).isInvertible()) {
428                         return ((AbstractSpecification<T>) ((DisjunctionSpecification<T>) negatedSpec).invert()).purify(true);
429                     } else {
430                         return purifyWithoutAnyInversionOfWrappedSpecs();
431                     }
432                 } else {
433                     return ((AbstractSpecification<T>) negatedSpec).purify(true);
434                 }
435             }
436             return purifyWithoutAnyInversionOfWrappedSpecs();
437 
438         } else if (negatedSpec instanceof ConjunctionSpecification) {
439             if (doPurifyInversions) {
440                 if (isOddNumber(numberOfLevelsOfInversions)) {
441                     if (((ConjunctionSpecification<T>) negatedSpec).isInvertible()) {
442                         return ((AbstractSpecification<T>) ((ConjunctionSpecification<T>) negatedSpec).invert()).purify(true);
443                     } else {
444                         return purifyWithoutAnyInversionOfWrappedSpecs();
445                     }
446                 } else {
447                     return ((AbstractSpecification<T>) negatedSpec).purify(true);
448                 }
449             }
450             return purifyWithoutAnyInversionOfWrappedSpecs();
451         }
452 
453         //throw new NotImplementedException();
454         // TODO: CollectionSpecifications...
455 
456         return purifyWithoutAnyInversionOfWrappedSpecs();
457     }
458 
459 
460     private AbstractSpecification<T> purifyWithoutAnyInversionOfWrappedSpecs() {
461         // TODO: get last 'not' when odd number and more than one wrapped not()
462         //return null;  //To change body of created methods use File | Settings | File Templates.
463 
464         // Lock down wrapped specifications
465         // TODO: do this all over...
466         this.specifications = Collections.unmodifiableSet(this.specifications);
467         return this;
468     }
469 }