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.text.ParseException;
20  import java.text.SimpleDateFormat;
21  import java.util.Collection;
22  import java.util.Date;
23  
24  import org.apache.commons.lang.Validate;
25  
26  import net.sourceforge.domian.entity.Entity;
27  
28  import static java.util.Arrays.asList;
29  import static net.sourceforge.domian.specification.CollectionSpecification.CollectionSpecificationScope;
30  
31  
32  /**
33   * Factory for creating specifications.
34   * <p/>
35   * This class is a collection of static factory methods for creating {@link net.sourceforge.domian.specification.Specification} objects.
36   * These methods are heavily aliased promoting humane interfaces with the noble hope of achieving some fluent expressions...
37   * <p/>
38   * Domian {@link Specification}s should only be created by this class.
39   *
40   * @author Eirik Torske
41   * @since 0.1
42   */
43  public final class SpecificationFactory {
44  
45      //////////////////////////////////////////////////////////////////////
46      // The subject (composite specification generator methods)
47      //
48      //////////////////////////////////////////////////////////////////////
49  
50      //////////////////////////////////////////////////////////////////////
51      // Typed specifications
52      //////////////////////////////////////////////////////////////////////
53  
54      public static <T> CompositeSpecification<T> createSpecificationFor(final Class<T> type) {
55          /* ConjunctionSpecification treated as default CompositeSpecification */
56          return new ConjunctionSpecification<T>(type);
57      }
58  
59      public static <T> CompositeSpecification<T> the(final Class<T> type) {
60          return createSpecificationFor(type);
61      }
62  
63      public static <T> CompositeSpecification<T> a(final Class<T> type) {
64          return createSpecificationFor(type);
65      }
66  
67      public static <T> CompositeSpecification<T> an(final Class<T> type) {
68          return createSpecificationFor(type);
69      }
70  
71      public static <T> CompositeSpecification<T> isA(final Class<T> type) {
72          return createSpecificationFor(type);
73      }
74  
75      public static <T> CompositeSpecification<T> isAn(final Class<T> type) {
76          return createSpecificationFor(type);
77      }
78  
79      public static <T> CompositeSpecification<T> all(final Class<T> type) {
80          return createSpecificationFor(type);
81      }
82  
83      public static <T> CompositeSpecification<T> instanceOf(final Class<T> type) {
84          return createSpecificationFor(type);
85      }
86  
87      public static <T> CompositeSpecification<T> instancesOf(final Class<T> type) {
88          return createSpecificationFor(type);
89      }
90  
91      public static <T> CompositeSpecification<T> instanceOfType(final Class<T> type) {
92          return createSpecificationFor(type);
93      }
94  
95      public static <T> CompositeSpecification<T> instancesOfType(final Class<T> type) {
96          return createSpecificationFor(type);
97      }
98  
99      public static <T> CompositeSpecification<T> anInstanceOfType(final Class<T> type) {
100         return createSpecificationFor(type);
101     }
102 
103     public static <T> CompositeSpecification<T> allOfType(final Class<T> type) {
104         return createSpecificationFor(type);
105     }
106 
107     public static <T> CompositeSpecification<T> allInstancesOfType(final Class<T> type) {
108         return createSpecificationFor(type);
109     }
110 
111     public static <T> CompositeSpecification<T> specify(final Class<T> type) {
112         return createSpecificationFor(type);
113     }
114 
115     public static <T> CompositeSpecification<T> specifyA(final Class<T> type) {
116         return createSpecificationFor(type);
117     }
118 
119     public static <T> CompositeSpecification<T> specifyAn(final Class<T> type) {
120         return createSpecificationFor(type);
121     }
122 
123     //////////////////////////////////////////////////////////////////////
124     // The conditions (leaf specification generator methods)
125     //
126     //////////////////////////////////////////////////////////////////////
127 
128     //////////////////////////////////////////////////////////////////////
129     // Misc. special cases
130     //////////////////////////////////////////////////////////////////////
131 
132     /** @return a {@link AlwaysFalseSpecification} instance */
133     public static Specification<?> createAlwaysFalseSpecification() {
134         return new AlwaysFalseSpecification();
135     }
136 
137     /** @return a {@link AlwaysFalseSpecification} instance */
138     public static Specification<?> createContradiction() {
139         return createAlwaysFalseSpecification();
140     }
141 
142     /** @return a {@link AlwaysTrueSpecification} instance */
143     public static Specification<?> createAlwaysTrueSpecification() {
144         return new AlwaysTrueSpecification();
145     }
146 
147     /** @return a {@link AlwaysTrueSpecification} instance */
148     public static Specification<?> createTautology() {
149         return createAlwaysTrueSpecification();
150     }
151 
152     /** @return a {@link NotNullSpecification} instance */
153     public static <T> Specification<T> createNotNullSpecification(final Class<T> type) {
154         return new NotNullSpecification<T>(type);
155     }
156 
157     /** @return a {@link NotNullSpecification}<code>&lt;java.lang.Object&gt;</code> instance */
158     public static Specification allObjects() {
159         return createNotNullSpecification(Object.class);
160     }
161 
162     /** @return a {@link NotNullSpecification}<code>&lt;net.sourceforge.domian.entity.Entity&gt;</code> instance */
163     public static Specification<? extends Entity> allEntities() {
164         return createNotNullSpecification(Entity.class);
165     }
166 
167     /** @return a {@link NotNullSpecification}<code>&lt;net.sourceforge.domian.entity.Entity&gt;</code> instance */
168     public static Specification<? extends Entity> entities() {
169         return createNotNullSpecification(Entity.class);
170     }
171 
172     /** @return a {@link NotNullSpecification}<code>&lt;net.sourceforge.domian.entity.Entity&gt;</code> instance */
173     public static Specification<? extends Entity> entity() {
174         return createNotNullSpecification(Entity.class);
175     }
176 
177     /** @return a negated {@link NotNullSpecification}<code>&lt;java.lang.Object&gt;</code> instance */
178     public static Specification<?> isNull() {
179         return not(isNotNull());
180     }
181 
182     /** @return a {@link NotNullSpecification}<code>&lt;java.lang.Object&gt;</code> instance */
183     public static Specification<?> isNotNull() {
184         return createNotNullSpecification(Object.class);
185     }
186 
187     /** @return a {@link DefaultValueSpecification} instance */
188     static <T> Specification<T> createDefaultValueOfTypeSpecification(final Class<T> type) {
189         return new DefaultValueSpecification<T>(type);
190     }
191 
192     /** @return a {@link DefaultValueSpecification} instance */
193     static <T> Specification<T> isDefaultValueOfType(final Class<T> type) {
194         return createDefaultValueOfTypeSpecification(type);
195     }
196 
197     /** @return a {@link DefaultValueSpecification} instance */
198     static <T> Specification<T> defaultValueOfType(final Class<T> type) {
199         return createDefaultValueOfTypeSpecification(type);
200     }
201 
202     /** @return a {@link DefaultValueSpecification}<code>&lt;java.lang.Number&gt;</code> instance */
203     public static Specification<Number> createDefaultNumberSpecification() {
204         return createDefaultValueOfTypeSpecification(Number.class);
205     }
206 
207     /** @return a {@link DefaultValueSpecification}<code>&lt;java.lang.Number&gt;</code> instance */
208     public static Specification<Number> isDefaultNumber() {
209         return createDefaultValueOfTypeSpecification(Number.class);
210     }
211 
212     /** @return a {@link DefaultValueSpecification}<code>&lt;java.lang.Number&gt;</code> instance */
213     public static Specification<Number> defaultNumber() {
214         return createDefaultValueOfTypeSpecification(Number.class);
215     }
216 
217     /** @return a {@link DefaultValueSpecification}<code>&lt;java.lang.String&gt;</code> instance */
218     public static Specification<String> createBlankStringSpecification() {
219         return createDefaultValueOfTypeSpecification(String.class);
220     }
221 
222     /** @return a {@link DefaultValueSpecification}<code>&lt;java.lang.String&gt;</code> instance */
223     public static Specification<String> isBlankString() {
224         return createDefaultValueOfTypeSpecification(String.class);
225     }
226 
227     /** @return a {@link DefaultValueSpecification}<code>&lt;java.lang.String&gt;</code> instance */
228     public static Specification<String> blankString() {
229         return createDefaultValueOfTypeSpecification(String.class);
230     }
231 
232     /** @return a {@link EqualIgnoreCaseStringSpecification}<code>&lt;java.lang.String&gt;</code> instance */
233     public static Specification<String> createEqualIgnoreCaseStringSpecification(final String string) {
234         return new EqualIgnoreCaseStringSpecification(string);
235     }
236 
237     /** @return a {@link EqualIgnoreCaseStringSpecification}<code>&lt;java.lang.String&gt;</code> instance */
238     public static Specification<String> equalIgnoringCase(final String string) {
239         return createEqualIgnoreCaseStringSpecification(string);
240     }
241 
242     /** @return a {@link EqualIgnoreCaseStringSpecification}<code>&lt;java.lang.String&gt;</code> instance */
243     public static Specification<String> equalsIgnoringCase(final String string) {
244         return createEqualIgnoreCaseStringSpecification(string);
245     }
246 
247     /** @return a {@link EqualIgnoreCaseStringSpecification}<code>&lt;java.lang.String&gt;</code> instance */
248     public static Specification<String> isEqualIgnoringCase(final String string) {
249         return createEqualIgnoreCaseStringSpecification(string);
250     }
251 
252     /** @return a {@link DateStringSpecification} instance */
253     public static Specification<String> createDateStringSpecification(final String dateString) {
254         return new DateStringSpecification(dateString);
255     }
256 
257     /** @return a {@link DateStringSpecification} instance */
258     public static Specification<String> isDate(final String dateString) {
259         return createDateStringSpecification(dateString);
260     }
261 
262     /** @return a {@link EnumNameStringSpecification} instance */
263     public static <E extends Enum> Specification<String> createEnumNameStringSpecification(Class<E> enumClass) {
264         return new EnumNameStringSpecification<E>(enumClass);
265     }
266 
267     /** @return a {@link EnumNameStringSpecification} instance */
268     public static <E extends Enum> Specification<String> isEnum(Class<E> enumClass) {
269         return createEnumNameStringSpecification(enumClass);
270     }
271 
272     //////////////////////////////////////////////////////////////////////
273     // Equality
274     //////////////////////////////////////////////////////////////////////
275 
276     /** @return a {@link EqualSpecification} instance */
277     public static <T> Specification<T> createEqualSpecification(final T value) {
278         return new EqualSpecification<T>(value);
279     }
280 
281     /** @return a {@link EqualSpecification} instance */
282     public static <T> Specification<T> anObjectEqualTo(final T value) {
283         return new EqualSpecification<T>(value);
284     }
285 
286     /** @return a {@link EqualSpecification} instance */
287     public static <T> Specification<T> objectEqualTo(final T value) {
288         return new EqualSpecification<T>(value);
289     }
290 
291     /** @return a {@link EqualSpecification} instance */
292     public static <T> Specification<T> isEqualTo(final T value) {
293         return createEqualSpecification(value);
294     }
295 
296     /** @return a {@link EqualSpecification} instance */
297     public static <T> Specification<T> equalTo(final T value) {
298         return createEqualSpecification(value);
299     }
300 
301     /** @return a {@link EqualSpecification} instance */
302     public static <T> Specification<T> exactly(final T value) {
303         return createEqualSpecification(value);
304     }
305 
306     /** @return a {@link EqualSpecification} instance */
307     public static <T> Specification<T> is(final T value) {
308         return createEqualSpecification(value);
309     }
310 
311     /** @return a {@link EqualSpecification}<code>&lt;java.util.Date&gt;</code> instance */
312     public static Specification<Date> isAtTheSameTimeAs(final Date date) {
313         return createEqualSpecification(date);
314     }
315 
316     /** @return a {@link EqualSpecification}<code>&lt;java.util.Date&gt;</code> instance */
317     public static Specification<Date> atTheSameTimeAs(final Date date) {
318         return createEqualSpecification(date);
319     }
320 
321     /** @return a {@link EqualSpecification}<code>&lt;java.util.Date&gt;</code> instance */
322     public static Specification<Date> at(final Date date) {
323         return createEqualSpecification(date);
324     }
325 
326     /** @return a {@link EqualSpecification}<code>&lt;java.lang.Boolean&gt;</code> instance */
327     public static Specification<Boolean> isTrue() {
328         return createEqualSpecification(Boolean.TRUE);
329     }
330 
331     /** @return a {@link EqualSpecification}<code>&lt;java.lang.Boolean&gt;</code> instance */
332     public static Specification<Boolean> isFalse() {
333         return createEqualSpecification(Boolean.FALSE);
334     }
335 
336     //////////////////////////////////////////////////////////////////////
337     // Equality (Regex variants)
338     //////////////////////////////////////////////////////////////////////
339 
340     /** @return a {@link RegularExpressionMatcherStringSpecification} instance */
341     static Specification<String> createRegularExpressionMatcherStringSpecification(final String regularExpression) {
342         return new RegularExpressionMatcherStringSpecification(regularExpression);
343     }
344 
345     /** @return a {@link RegularExpressionMatcherStringSpecification} instance */
346     public static Specification<String> matchesRegularExpression(final String regularExpression) {
347         return createRegularExpressionMatcherStringSpecification(regularExpression);
348     }
349 
350     /** @return a {@link RegularExpressionMatcherStringSpecification} instance */
351     public static Specification<String> matchesRegex(final String regularExpression) {
352         return createRegularExpressionMatcherStringSpecification(regularExpression);
353     }
354 
355     /** @return a {@link RegularExpressionMatcherStringSpecification} instance */
356     public static Specification<String> matches(final String regularExpression) {
357         return createRegularExpressionMatcherStringSpecification(regularExpression);
358     }
359 
360     //////////////////////////////////////////////////////////////////////
361     // Equality (Wildcard variants)
362     //////////////////////////////////////////////////////////////////////
363 
364     /** @return a {@link WildcardExpressionMatcherStringSpecification} instance */
365     static Specification<String> createWildcardExpressionMatcherStringSpecification(final String wildcardExpression) {
366         return new WildcardExpressionMatcherStringSpecification(wildcardExpression);
367     }
368 
369     /** @return a {@link WildcardExpressionMatcherStringSpecification} instance */
370     public static Specification<String> matchesWildcardExpression(final String wildcardExpression) {
371         return createWildcardExpressionMatcherStringSpecification(wildcardExpression);
372     }
373 
374     /** @return a {@link RegularExpressionMatcherStringSpecification} instance */
375     public static Specification<String> like(final String wildcardExpression) {
376         return createWildcardExpressionMatcherStringSpecification(wildcardExpression);
377     }
378 
379     /** @return a {@link WildcardExpressionMatcherIgnoreCaseStringSpecification} instance */
380     static Specification<String> createWildcardExpressionIgnoringCaseMatcherStringSpecification(final String wildcardExpression) {
381         return new WildcardExpressionMatcherIgnoreCaseStringSpecification(wildcardExpression);
382     }
383 
384     /** @return a {@link WildcardExpressionMatcherIgnoreCaseStringSpecification} instance */
385     public static Specification<String> matchesWildcardExpressionIgnoringCase(final String wildcardExpression) {
386         return createWildcardExpressionIgnoringCaseMatcherStringSpecification(wildcardExpression);
387     }
388 
389     //////////////////////////////////////////////////////////////////////
390     // Less than
391     //////////////////////////////////////////////////////////////////////
392 
393     /** @return a {@link LessThanSpecification} instance */
394     static <T extends Comparable> Specification<T> createLessThanSpecification(final T value) {
395         return new LessThanSpecification<T>(value);
396     }
397 
398     /** @return a {@link LessThanSpecification} instance */
399     public static <T extends Comparable> Specification<T> isLessThan(final T value) {
400         return createLessThanSpecification(value);
401     }
402 
403     /** @return a {@link LessThanSpecification} instance */
404     public static <T extends Comparable> Specification<T> lessThan(final T value) {
405         return createLessThanSpecification(value);
406     }
407 
408     /** @return a {@link LessThanSpecification} instance */
409     public static <T extends Comparable> Specification<T> isBefore(final T value) {
410         return createLessThanSpecification(value);
411     }
412 
413     /** @return a {@link LessThanSpecification} instance */
414     public static <T extends Comparable> Specification<T> before(final T value) {
415         return createLessThanSpecification(value);
416     }
417 
418     /** @return a {@link LessThanSpecification}<code>&lt;java.util.Date&gt;</code> instance */
419     public static Specification<Date> isBefore(final String dateString) {
420         return before(dateString);
421     }
422 
423     /** @return a {@link LessThanSpecification}<code>&lt;java.util.Date&gt;</code> instance */
424     public static Specification<Date> before(final String dateString) {
425         try {
426             final String datePattern = validateDateString(dateString);
427             return createLessThanSpecification(new SimpleDateFormat(datePattern).parse(dateString));
428 
429         } catch (ParseException e) {
430             throw new IllegalArgumentException("\"" + dateString + "\"" + DATE_PARSING_ERROR_MSG_ENDING);
431         }
432     }
433 
434     //////////////////////////////////////////////////////////////////////
435     // Less than or equal
436     //////////////////////////////////////////////////////////////////////
437 
438     /** @return a {@link DisjunctionSpecification} instance containing a {@link LessThanSpecification} and a {@link EqualSpecification} */
439     static <T extends Comparable> Specification<T> createLessThanOrEqualSpecification(final T value) {
440         return anyOf(lessThan(value), equalTo(value));
441     }
442 
443     /** @return a {@link DisjunctionSpecification} instance containing a {@link LessThanSpecification} and a {@link EqualSpecification} */
444     public static <T extends Comparable> Specification<T> isLessThanOrEqualTo(final T value) {
445         return createLessThanOrEqualSpecification(value);
446     }
447 
448     /** @return a {@link DisjunctionSpecification} instance containing a {@link LessThanSpecification} and a {@link EqualSpecification} */
449     public static <T extends Comparable> Specification<T> lessThanOrEqualTo(final T value) {
450         return createLessThanOrEqualSpecification(value);
451     }
452 
453     /** @return a {@link DisjunctionSpecification} instance containing a {@link LessThanSpecification} and a {@link EqualSpecification} */
454     public static <T extends Comparable> Specification<T> atMost(final T value) {
455         return createLessThanOrEqualSpecification(value);
456     }
457 
458     /** @return a {@link DisjunctionSpecification} instance containing a {@link LessThanSpecification} and a {@link EqualSpecification} */
459     public static <T extends Comparable> Specification<T> isBeforeOrAtTheSameTimeAs(final T dateOrLongValue) {
460         return createLessThanOrEqualSpecification(dateOrLongValue);
461     }
462 
463     /** @return a {@link DisjunctionSpecification} instance containing a {@link LessThanSpecification} and a {@link EqualSpecification} */
464     public static <T extends Comparable> Specification<T> beforeOrAtTheSameTimeAs(final T dateOfLongValue) {
465         return createLessThanOrEqualSpecification(dateOfLongValue);
466     }
467 
468     /** @return a {@link DisjunctionSpecification} instance containing a {@link LessThanSpecification} and a {@link EqualSpecification} */
469     public static Specification<Date> isBeforeOrAtTheSameTimeAs(final String dateString) {
470         return beforeOrAtTheSameTimeAs(dateString);
471     }
472 
473     /** @return a {@link DisjunctionSpecification} instance containing a {@link LessThanSpecification} and a {@link EqualSpecification} */
474     public static Specification<Date> beforeOrAtTheSameTimeAs(final String dateString) {
475         try {
476             return createLessThanOrEqualSpecification(new SimpleDateFormat(validateDateString(dateString)).parse(dateString));
477 
478         } catch (ParseException e) {
479             throw new IllegalArgumentException("\"" + dateString + "\"" + DATE_PARSING_ERROR_MSG_ENDING);
480         }
481     }
482 
483     //////////////////////////////////////////////////////////////////////
484     // Greater than
485     //////////////////////////////////////////////////////////////////////
486 
487     /** @return a {@link GreaterThanSpecification} instance */
488     static <T extends Comparable> Specification<T> createGreaterThanSpecification(final T value) {
489         return new GreaterThanSpecification<T>(value);
490     }
491 
492     /** @return a {@link GreaterThanSpecification} instance */
493     public static <T extends Comparable> Specification<T> isGreaterThan(final T value) {
494         return createGreaterThanSpecification(value);
495     }
496 
497     /** @return a {@link GreaterThanSpecification} instance */
498     public static <T extends Comparable> Specification<T> greaterThan(final T value) {
499         return createGreaterThanSpecification(value);
500     }
501 
502     /** @return a {@link GreaterThanSpecification} instance */
503     public static <T extends Comparable> Specification<T> moreThan(final T value) {
504         return createGreaterThanSpecification(value);
505     }
506 
507     /** @return a {@link GreaterThanSpecification} instance */
508     public static <T extends Comparable> Specification<T> isAfter(final T value) {
509         return createGreaterThanSpecification(value);
510     }
511 
512     /** @return a {@link GreaterThanSpecification} instance */
513     public static <T extends Comparable> Specification<T> after(final T value) {
514         return createGreaterThanSpecification(value);
515     }
516 
517     /** @return a {@link GreaterThanSpecification}<code>&lt;java.util.Date&gt;</code> instance */
518     public static Specification<Date> isAfter(final String dateString) {
519         return after(dateString);
520     }
521 
522     /** @return a {@link GreaterThanSpecification}<code>&lt;java.util.Date&gt;</code> instance */
523     public static Specification<Date> after(final String dateString) {
524         try {
525             final String datePattern = validateDateString(dateString);
526             return createGreaterThanSpecification(new SimpleDateFormat(datePattern).parse(dateString));
527 
528         } catch (ParseException e) {
529             throw new IllegalArgumentException("\"" + dateString + "\"" + DATE_PARSING_ERROR_MSG_ENDING);
530         }
531     }
532 
533     //////////////////////////////////////////////////////////////////////
534     // Greater than or equal
535     //////////////////////////////////////////////////////////////////////
536 
537     /** @return a {@link DisjunctionSpecification} instance containing a {@link GreaterThanSpecification} and a {@link EqualSpecification} */
538     static <T extends Comparable> Specification<T> createGreaterThanOrEqualSpecification(final T value) {
539         return anyOf(greaterThan(value), equalTo(value));
540     }
541 
542     /** @return a {@link DisjunctionSpecification} instance containing a {@link GreaterThanSpecification} and a {@link EqualSpecification} */
543     public static <T extends Comparable> Specification<T> isGreaterThanOrEqualTo(final T value) {
544         return createGreaterThanOrEqualSpecification(value);
545     }
546 
547     /** @return a {@link DisjunctionSpecification} instance containing a {@link GreaterThanSpecification} and a {@link EqualSpecification} */
548     public static <T extends Comparable> Specification<T> greaterThanOrEqualTo(final T value) {
549         return createGreaterThanOrEqualSpecification(value);
550     }
551 
552     /** @return a {@link DisjunctionSpecification} instance containing a {@link GreaterThanSpecification} and a {@link EqualSpecification} */
553     public static <T extends Comparable> Specification<T> atLeast(final T value) {
554         return createGreaterThanOrEqualSpecification(value);
555     }
556 
557     /** @return a {@link DisjunctionSpecification} instance containing a {@link GreaterThanSpecification} and a {@link EqualSpecification} */
558     public static <T extends Comparable> Specification<T> isAfterOrAtTheSameTimeAs(final T dateOrLongValue) {
559         return createGreaterThanOrEqualSpecification(dateOrLongValue);
560     }
561 
562     /** @return a {@link DisjunctionSpecification} instance containing a {@link GreaterThanSpecification} and a {@link EqualSpecification} */
563     public static <T extends Comparable> Specification<T> afterOrAtTheSameTimeAs(final T dateOrLongValue) {
564         return createGreaterThanOrEqualSpecification(dateOrLongValue);
565     }
566 
567     /** @return a {@link DisjunctionSpecification} instance containing a {@link GreaterThanSpecification} and a {@link EqualSpecification} */
568     public static Specification<Date> isAfterOrAtTheSameTimeAs(final String dateString) {
569         return afterOrAtTheSameTimeAs(dateString);
570     }
571 
572     /** @return a {@link DisjunctionSpecification} instance containing a {@link GreaterThanSpecification} and a {@link EqualSpecification} */
573     public static Specification<Date> afterOrAtTheSameTimeAs(final String dateString) {
574         try {
575             return createLessThanOrEqualSpecification(new SimpleDateFormat(validateDateString(dateString)).parse(dateString));
576 
577         } catch (ParseException e) {
578             throw new IllegalArgumentException("\"" + dateString + "\"" + DATE_PARSING_ERROR_MSG_ENDING);
579         }
580     }
581 
582     //////////////////////////////////////////////////////////////////////
583     // The conditions (composite specification wrappers)
584     //
585     //////////////////////////////////////////////////////////////////////
586 
587     //////////////////////////////////////////////////////////////////////
588     // Conjunction (AND)
589     //////////////////////////////////////////////////////////////////////
590 
591     /** @return a {@link ConjunctionSpecification} instance */
592     @SuppressWarnings("unchecked")
593     public static <T> Specification<T> allOf(final Specification<T>... specifications) {
594         Validate.notNull(specifications, "Specification varargs cannot be null");
595         Validate.isTrue(specifications.length > 0, "Specification varargs cannot be empty");
596         if (specifications.length == 1) {
597             Validate.notNull(specifications[0], "Specification varargs cannot be null");
598         }
599         final Specification<T> firstSpecParameter = specifications[0];
600         final ConjunctionSpecification<T> conjunctionSpecification;
601         // TODO: this is an ugly workaround for the missing CollectionSpecification.getType()... help!
602         if (firstSpecParameter instanceof CollectionSpecification) {
603             /* @SuppressWarnings("unchecked") -> "I solemnly swear that this statement will not throw any ClassCastException!" -eirik torske- */
604             /* Type is resolved above */
605             conjunctionSpecification = new ConjunctionSpecification(Collection.class);
606             conjunctionSpecification.specifications.addAll(asList(specifications));
607         } else {
608             conjunctionSpecification = new ConjunctionSpecification<T>(firstSpecParameter.getType());
609             conjunctionSpecification.specifications.addAll(asList(specifications));
610         }
611         return conjunctionSpecification.purify(true);
612     }
613 
614     /** @return a {@link ConjunctionSpecification} instance */
615     public static <T> Specification<T> shouldBeAllOf(final Specification<T>... specifications) {
616         return allOf(specifications);
617     }
618 
619     /** @return a {@link ConjunctionSpecification} instance */
620     public static <T> Specification<T> shouldBeBoth(final Specification<T>... specifications) {
621         return allOf(specifications);
622     }
623 
624     /** @return a {@link ConjunctionSpecification} instance */
625     public static <T> Specification<T> shouldBe(final Specification<T>... specifications) {
626         return allOf(specifications);
627     }
628 
629     /** @return a {@link ConjunctionSpecification} instance */
630     public static <T> Specification<T> isAllOf(final Specification<T>... specifications) {
631         return allOf(specifications);
632     }
633 
634     /** @return a {@link ConjunctionSpecification} instance */
635     public static <T> Specification<T> isBoth(final Specification<T>... specifications) {
636         return allOf(specifications);
637     }
638 
639     /** @return a {@link ConjunctionSpecification} instance */
640     public static <T> Specification<T> both(final Specification<T>... specifications) {
641         return allOf(specifications);
642     }
643 
644     //////////////////////////////////////////////////////////////////////
645     // Disjunction (OR) (for specifications)
646     //////////////////////////////////////////////////////////////////////
647 
648     /** @return a {@link DisjunctionSpecification} instance */
649     @SuppressWarnings("unchecked")
650     public static <T> Specification<T> anyOf(final Specification<T>... specifications) {
651         Validate.notNull(specifications, "Specification varargs cannot be null");
652         Validate.isTrue(specifications.length > 0, "Specification varargs cannot be empty");
653         if (specifications.length == 1) {
654             Validate.notNull(specifications[0], "Specification varargs cannot be null");
655         }
656         final Specification<T> firstSpecParameter = specifications[0];
657         final DisjunctionSpecification<T> disjunctionSpecification;
658         // TODO: this is an ugly workaround for the missing CollectionSpecification.getType()... help!
659         if (firstSpecParameter instanceof CollectionSpecification) {
660             /* @SuppressWarnings("unchecked") -> "I solemnly swear that this statement will not throw any ClassCastException!" -eirik torske- */
661             /* Type is resolved above */
662             disjunctionSpecification = new DisjunctionSpecification(Collection.class);
663             disjunctionSpecification.specifications.addAll(asList(specifications));
664         } else {
665             disjunctionSpecification = new DisjunctionSpecification<T>(firstSpecParameter.getType());
666             disjunctionSpecification.specifications.addAll(asList(specifications));
667         }
668         return disjunctionSpecification.purify(true);
669     }
670 
671     /** @return a {@link DisjunctionSpecification} instance */
672     public static <T> Specification<T> shouldBeOneOf(final Specification<T>... specifications) {
673         return anyOf(specifications);
674     }
675 
676     /** @return a {@link DisjunctionSpecification} instance */
677     public static <T> Specification<T> shouldBeEitherOf(final Specification<T>... specifications) {
678         return anyOf(specifications);
679     }
680 
681     /** @return a {@link DisjunctionSpecification} instance */
682     public static <T> Specification<T> isOneOf(final Specification<T>... specifications) {
683         return anyOf(specifications);
684     }
685 
686     /** @return a {@link DisjunctionSpecification} instance */
687     public static <T> Specification<T> isEitherOf(final Specification<T>... specifications) {
688         return anyOf(specifications);
689     }
690 
691     /** @return a {@link DisjunctionSpecification} instance */
692     public static <T> Specification<T> isEitherThe(final Specification<T>... specifications) {
693         return anyOf(specifications);
694     }
695 
696     /** @return a {@link DisjunctionSpecification} instance */
697     public static <T> Specification<T> isEither(final Specification<T>... specifications) {
698         return anyOf(specifications);
699     }
700 
701     /** @return a {@link DisjunctionSpecification} instance */
702     public static <T> Specification<T> oneOf(final Specification<T>... specifications) {
703         return anyOf(specifications);
704     }
705 
706     /** @return a {@link DisjunctionSpecification} instance */
707     public static <T> Specification<T> eitherOf(final Specification<T>... specifications) {
708         return anyOf(specifications);
709     }
710 
711     /** @return a {@link DisjunctionSpecification} instance */
712     public static <T> Specification<T> either(final Specification<T>... specifications) {
713         return anyOf(specifications);
714     }
715 
716     /** @return a {@link DisjunctionSpecification} instance */
717     public static <T> Specification<T> in(final Specification<T>... specifications) {
718         return anyOf(specifications);
719     }
720 
721     //////////////////////////////////////////////////////////////////////
722     // Disjunction (OR) (for values)
723     //////////////////////////////////////////////////////////////////////
724 
725     /** @return a {@link DisjunctionSpecification} instance */
726     @SuppressWarnings("unchecked")
727     public static <F> Specification<F> anyOf(final F... values) {
728         /* @SuppressWarnings("unchecked") -> "I solemnly swear that this statement will not throw any ClassCastException!" -eirik torske- */
729         final Specification<F>[] specsArray = new Specification[values.length];
730         for (int i = 0; i < values.length; ++i) {
731             if (values[i] instanceof Specification) {
732                 /* @SuppressWarnings("unchecked") -> "I solemnly swear that this statement will not throw any ClassCastException!" -eirik torske- */
733                 /* Type is resolved above */
734                 specsArray[i] = (Specification<F>) values[i];
735             } else {
736                 specsArray[i] = createEqualSpecification(values[i]);
737             }
738         }
739         return anyOf(specsArray);
740     }
741 
742     /** @return a {@link DisjunctionSpecification} instance */
743     public static <F> Specification<F> shouldBeOneOf(final F... values) {
744         return anyOf(values);
745     }
746 
747     /** @return a {@link DisjunctionSpecification} instance */
748     public static <F> Specification<F> shouldBeEitherOf(final F... values) {
749         return anyOf(values);
750     }
751 
752     /** @return a {@link DisjunctionSpecification} instance */
753     public static <F> Specification<F> isOneOf(final F... values) {
754         return anyOf(values);
755     }
756 
757     /** @return a {@link DisjunctionSpecification} instance */
758     public static <F> Specification<F> isEitherOf(final F... values) {
759         return anyOf(values);
760     }
761 
762     /** @return a {@link DisjunctionSpecification} instance */
763     public static <F> Specification<F> isEitherThe(final F... values) {
764         return anyOf(values);
765     }
766 
767     /** @return a {@link DisjunctionSpecification} instance */
768     public static <F> Specification<F> isEither(final F... values) {
769         return anyOf(values);
770     }
771 
772     /** @return a {@link DisjunctionSpecification} instance */
773     public static <F> Specification<F> oneOf(final F... values) {
774         return anyOf(values);
775     }
776 
777     /** @return a {@link DisjunctionSpecification} instance */
778     public static <F> Specification<F> eitherOf(final F... values) {
779         return anyOf(values);
780     }
781 
782     /** @return a {@link DisjunctionSpecification} instance */
783     public static <F> Specification<F> either(final F... values) {
784         return anyOf(values);
785     }
786 
787     /** @return a {@link DisjunctionSpecification} instance */
788     public static <F> Specification<F> in(final F... values) {
789         return anyOf(values);
790     }
791 
792     //////////////////////////////////////////////////////////////////////
793     // Joint denial conjunction (NOR)
794     //////////////////////////////////////////////////////////////////////
795 
796     /** @return a {@link JointDenialSpecification} instance */
797     @SuppressWarnings("unchecked")
798     public static <T> Specification<T> neitherOf(final Specification<T>... specifications) {
799         Validate.notNull(specifications, "Specification varargs cannot be null");
800         Validate.isTrue(specifications.length > 0, "Specification varargs cannot be empty");
801         if (specifications.length == 1) {
802             Validate.notNull(specifications[0], "Specification varargs cannot be null");
803         }
804         final Specification<T> firstSpecParameter = specifications[0];
805         final JointDenialSpecification<T> jointDenialSpecification;
806         // TODO: this is an ugly workaround for the missing CollectionSpecification.getType()... help!
807         if (firstSpecParameter instanceof CollectionSpecification) {
808             /* @SuppressWarnings("unchecked") -> "I solemnly swear that this statement will not throw any ClassCastException!" -eirik torske- */
809             /* Type is resolved above */
810             jointDenialSpecification = new JointDenialSpecification(Collection.class);
811             jointDenialSpecification.specifications.addAll(asList(specifications));
812         } else {
813             jointDenialSpecification = new JointDenialSpecification<T>(firstSpecParameter.getType());
814             jointDenialSpecification.specifications.addAll(asList(specifications));
815         }
816         return jointDenialSpecification.purify(false);
817     }
818 
819     /** @return a {@link JointDenialSpecification} instance */
820     public static <T> Specification<T> not(final Specification<T> specification) {
821         return neitherOf(specification);
822     }
823 
824     /** @return a {@link JointDenialSpecification} instance */
825     public static <T> Specification<T> not(final T object) {
826         return not(equalTo(object));
827     }
828 
829     //////////////////////////////////////////////////////////////////////
830     // Single specification wrappers
831     //////////////////////////////////////////////////////////////////////
832 
833     public static <T> Specification<T> isSatisfiedBy(final Specification<T> specification) {
834         return allOf(specification);
835     }
836 
837     public static <T> Specification<T> a(final Specification<T> specification) {
838         return isSatisfiedBy(specification);
839     }
840 
841     public static <T> Specification<T> an(final Specification<T> specification) {
842         return isSatisfiedBy(specification);
843     }
844 
845     public static <T> Specification<T> is(final Specification<T> specification) {
846         return isSatisfiedBy(specification);
847     }
848 
849     public static <T> Specification<T> isA(final Specification<T> specification) {
850         return isSatisfiedBy(specification);
851     }
852 
853     public static <T> Specification<T> isAn(final Specification<T> specification) {
854         return isSatisfiedBy(specification);
855     }
856 
857     public static <T> Specification<T> are(final Specification<T> specification) {
858         return isSatisfiedBy(specification);
859     }
860 
861     public static <T> Specification<T> isFrom(final Specification<T> specification) {
862         return isSatisfiedBy(specification);
863     }
864 
865     //////////////////////////////////////////////////////////////////////
866     // Collection specifications
867     //////////////////////////////////////////////////////////////////////
868 
869     /** @return a {@link CollectionSpecification} instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#SIZE"><code>CollectionSpecificationScope.SIZE</code></a> mode */
870     public static <F> CollectionSpecification<F> hasSize(final Specification<Integer> collectionSpecification, Class<F> elementType) {
871         return new CollectionSpecification<F>(CollectionSpecificationScope.SIZE, collectionSpecification, new NotNullSpecification<F>(elementType));
872     }
873 
874     /** @return a {@link CollectionSpecification} instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#SIZE"><code>CollectionSpecificationScope.SIZE</code></a> mode */
875     public static <F> CollectionSpecification<F> haveSize(final Specification<Integer> collectionSpecification, Class<F> elementType) {
876         return hasSize(collectionSpecification, elementType);
877     }
878 
879     /** @return a {@link CollectionSpecification} instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#SIZE"><code>CollectionSpecificationScope.SIZE</code></a> mode */
880     public static <F> CollectionSpecification<F> hasSizeOf(final Specification<Integer> collectionSpecification, Class<F> elementType) {
881         return hasSize(collectionSpecification, elementType);
882     }
883 
884     /** @return a {@link CollectionSpecification} instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#SIZE"><code>CollectionSpecificationScope.SIZE</code></a> mode */
885     public static <F> CollectionSpecification<F> haveSizeOf(final Specification<Integer> collectionSpecification, Class<F> elementType) {
886         return hasSize(collectionSpecification, elementType);
887     }
888 
889     /** @return a {@link CollectionSpecification}<code>&lt;java.lang.Object&gt;</code> instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#SIZE"><code>CollectionSpecificationScope.SIZE</code></a> mode */
890     public static Specification<?> hasSize(final Specification<Integer> collectionSpecification) {
891         return new CollectionSpecification<Object>(CollectionSpecificationScope.SIZE, collectionSpecification, Object.class);
892     }
893 
894     /** @return a {@link CollectionSpecification}<code>&lt;java.lang.Object&gt;</code> instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#SIZE"><code>CollectionSpecificationScope.SIZE</code></a> mode */
895     public static Specification<?> haveSize(final Specification<Integer> collectionSpecification) {
896         return hasSize(collectionSpecification);
897     }
898 
899     /** @return a {@link CollectionSpecification}<code>&lt;java.lang.Object&gt;</code> instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#SIZE"><code>CollectionSpecificationScope.SIZE</code></a> mode */
900     public static Specification<?> hasSizeOf(final Specification<Integer> collectionSpecification) {
901         return hasSize(collectionSpecification);
902     }
903 
904     /** @return a {@link CollectionSpecification}<code>&lt;java.lang.Object&gt;</code> instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#SIZE"><code>CollectionSpecificationScope.SIZE</code></a> mode */
905     public static Specification<?> haveSizeOf(final Specification<Integer> collectionSpecification) {
906         return hasSize(collectionSpecification);
907     }
908 
909     /** @return a {@link CollectionSpecification}<code>&lt;java.lang.Object&gt;</code> instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#SIZE"><code>CollectionSpecificationScope.SIZE</code></a> mode */
910     public static Specification<?> isEmpty() {
911         return hasSize(equalTo(0));
912     }
913 
914     /** @return a {@link CollectionSpecification}<code>&lt;java.lang.Object&gt;</code> instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#SIZE"><code>CollectionSpecificationScope.SIZE</code></a> mode */
915     public static Specification<?> empty() {
916         return hasSize(equalTo(0));
917     }
918 
919     /** @return a {@link CollectionSpecification} instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#NUMBER_OF_APPROVED_ELEMENTS"><code>CollectionSpecificationScope.NUMBER_OF_APPROVED_ELEMENTS</code></a> mode */
920     public static <F> CollectionSpecification<F> include(final Specification<Integer> collectionSpecification, final Specification<F> elementSpecification) {
921         return new CollectionSpecification<F>(CollectionSpecificationScope.NUMBER_OF_APPROVED_ELEMENTS, collectionSpecification, elementSpecification);
922     }
923 
924     /** @return a {@link CollectionSpecification} instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#NUMBER_OF_APPROVED_ELEMENTS"><code>CollectionSpecificationScope.NUMBER_OF_APPROVED_ELEMENTS</code></a> mode */
925     public static <F> CollectionSpecification<F> includes(final Specification<Integer> collectionSpecification, final Specification<F> elementSpecification) {
926         return include(collectionSpecification, elementSpecification);
927     }
928 
929     /** @return a {@link CollectionSpecification} instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#PERCENTAGE_OF_APPROVED_ELEMENTS"><code>CollectionSpecificationScope.PERCENTAGE_OF_APPROVED_ELEMENTS</code></a> mode */
930     public static <F> CollectionSpecification<F> includeAPercentageOf(Specification<Integer> collectionSpecification, Specification<F> elementSpecification) {
931         return new CollectionSpecification<F>(CollectionSpecificationScope.PERCENTAGE_OF_APPROVED_ELEMENTS, collectionSpecification, elementSpecification);
932     }
933 
934     /** @return a {@link CollectionSpecification} instance in <a href="CollectionSpecification.CollectionSpecificationScope.html#PERCENTAGE_OF_APPROVED_ELEMENTS"><code>CollectionSpecificationScope.PERCENTAGE_OF_APPROVED_ELEMENTS</code></a> mode */
935     public static <F> CollectionSpecification<F> includesAPercentageOf(Specification<Integer> collectionSpecification, Specification<F> elementSpecification) {
936         return includeAPercentageOf(collectionSpecification, elementSpecification);
937     }
938 
939 
940     //////////////////////////////////////////////////////////////////////
941     // Helper methods
942     //////////////////////////////////////////////////////////////////////
943     private static final String DATE_PARSING_ERROR_MSG_ENDING = " is not recognized as a valid date string -" +
944                                                                 " use a method with java.util.Date as parameter type to see whether" +
945                                                                 " the provided date parameter is actually illegal, or expressed in a not-supported format";
946 
947     private static String validateDateString(String dateString) {
948         if (dateString.length() != 8 && dateString.length() != 10) {
949             throw new IllegalArgumentException("\"" + dateString + "\"" + DATE_PARSING_ERROR_MSG_ENDING);
950         }
951         if (dateString.length() == 8) {
952             final DateStringSpecification spec = new DateStringSpecification("yyyyMMdd");
953             if (spec.isSatisfiedBy(dateString)) {
954                 return spec.getValue();
955             }
956         } else {
957             if (dateString.contains(".")) {
958                 if (dateString.charAt(2) == '.') {
959                     final DateStringSpecification spec = new DateStringSpecification("dd.MM.yyyy");
960                     if (spec.isSatisfiedBy(dateString)) {
961                         return spec.getValue();
962                     }
963                 }
964                 final DateStringSpecification spec = new DateStringSpecification("yyyy.MM.dd");
965                 if (spec.isSatisfiedBy(dateString)) {
966                     return spec.getValue();
967                 }
968             } else if (dateString.contains("-")) {
969                 if (dateString.charAt(2) == '-') {
970                     final DateStringSpecification spec = new DateStringSpecification("dd-MM-yyyy");
971                     if (spec.isSatisfiedBy(dateString)) {
972                         return spec.getValue();
973                     }
974                 }
975                 final DateStringSpecification spec = new DateStringSpecification("yyyy-MM-dd");
976                 if (spec.isSatisfiedBy(dateString)) {
977                     return spec.getValue();
978                 }
979             } else if (dateString.contains("/")) {
980                 if (dateString.charAt(2) == '/') {
981                     final DateStringSpecification spec = new DateStringSpecification("dd/MM/yyyy");
982                     if (spec.isSatisfiedBy(dateString)) {
983                         return spec.getValue();
984                     }
985                 }
986                 final DateStringSpecification spec = new DateStringSpecification("yyyy/MM/dd");
987                 if (spec.isSatisfiedBy(dateString)) {
988                     return spec.getValue();
989                 }
990             }
991         }
992         throw new IllegalArgumentException("\"" + dateString + "\"" + DATE_PARSING_ERROR_MSG_ENDING);
993     }
994 }