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.Set;
20
21 import org.apache.commons.lang.NotImplementedException;
22 import org.apache.commons.lang.Validate;
23 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
24
25 import net.sourceforge.domian.util.ReflectionUtils;
26
27 import static java.lang.Boolean.FALSE;
28 import static java.lang.Boolean.TRUE;
29
30
31
32
33
34
35
36
37
38 abstract class AbstractSpecification<T> implements Specification<T> {
39
40
41 protected volatile Class<T> type;
42
43
44 @SuppressWarnings("unchecked")
45 private synchronized Class<T> createType() {
46
47
48
49
50
51 if (this.type == null) {
52
53 this.type = (Class<T>) ReflectionUtils.getTypeArguments(AbstractSpecification.class, getClass()).get(0);
54 return this.type;
55 }
56 throw new IllegalStateException("This method should not be invoked unless type is null");
57 }
58
59
60 @Override
61 public Class<T> getType() {
62 return this.type == null ? createType() : this.type;
63 }
64
65
66 @Override
67 public Boolean isGeneralizationOf(final Specification<? extends T> specification) {
68
69
70 Validate.notNull(specification, "Specification parameter cannot be null");
71 return this.equals(specification);
72 }
73
74
75 @Override
76 public Boolean isSpecialCaseOf(final Specification<? super T> specification) {
77
78
79 Validate.notNull(specification, "Specification parameter cannot be null");
80 return this.equals(specification);
81 }
82
83
84 @Override
85 public Boolean isDisjointWith(final Specification<?> specification) {
86 Validate.notNull(specification, "Specification parameter cannot be null");
87 if (specification instanceof JointDenialSpecification) {
88 return specification.isDisjointWith(this);
89 }
90 return (this == specification || this.equals(specification)) ? FALSE : TRUE;
91 }
92
93
94
95
96
97 public Boolean isIntersectionOf(final Specification specification) {
98 Validate.notNull(specification, "Specification parameter cannot be null");
99
100 throw new NotImplementedException();
101 }
102
103
104
105
106 public Boolean intersectsWith(final Specification specification) {
107 return isIntersectionOf(specification);
108 }
109
110
111 @Override
112 public <F> CompositeSpecification<T> where(final String accessibleObjectName, final Specification<F> accessibleObjectSpecification) {
113 throw new UnsupportedOperationException("'where' clause is applicable only for CompositeSpecification instances");
114 }
115
116
117 @Override
118 public CompositeSpecification<T> and(final Specification<? super T> otherSpecification) {
119
120
121
122
123
124 Validate.notNull(otherSpecification, "Specification parameter cannot be null");
125 if (!ReflectionUtils.canCastAtLeastOneWay(this.getType(), otherSpecification.getType())) {
126 throw new IllegalArgumentException("Cannot create conjunction of a Specification<" + this.getType().getName() + "> and a Specification<" + otherSpecification.getType().getName() + ">");
127 }
128 if (this.isDisjointWith(otherSpecification)) {
129 throw new IllegalArgumentException("Cannot create a conjunction out of two disjoint specifications");
130 }
131 return (CompositeSpecification<T>) SpecificationFactory.allOf(this, (Specification<T>) otherSpecification);
132 }
133
134
135 @Override
136 public CompositeSpecification<T> or(final Specification<? super T> otherSpecification) {
137
138
139
140
141
142 return (CompositeSpecification<T>) SpecificationFactory.eitherOf(this, otherSpecification);
143 }
144
145
146
147
148
149
150
151
152
153
154
155 protected Boolean hasConjunction() {
156 return FALSE;
157 }
158
159
160
161 protected Boolean hasDisjunction() {
162 return FALSE;
163 }
164
165
166
167
168
169
170
171
172
173 protected void getAllSpecifications(final Set<Specification<?>> specificationSet) {
174 Validate.notNull(specificationSet, "Set of specifications parameter cannot be null");
175 specificationSet.add(this);
176 }
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209 protected AbstractSpecification<T> purify(final boolean doPurifyInversions) {
210
211 return this;
212 }
213
214
215
216
217
218
219
220
221 protected Boolean isInvertible() {
222 return FALSE;
223 }
224
225 protected Specification<T> invert() {
226 throw new UnsupportedOperationException();
227 }
228
229
230 protected static <T> Boolean containsValueBoundSpecificationsOnly(final AbstractCompositeSpecification<T> compositeSpecification) {
231 if (compositeSpecification.specifications.isEmpty()) {
232 return FALSE;
233 }
234 for (final Specification<?> spec : compositeSpecification.specifications) {
235 if (!(spec instanceof ValueBoundSpecification)) {
236 return FALSE;
237 }
238 }
239 return TRUE;
240 }
241
242
243 protected <T> Boolean containsSimpleCompositesOnly(final AbstractCompositeSpecification<T> compositeSpecification) {
244 if (compositeSpecification.specifications.isEmpty()) {
245 return FALSE;
246 }
247 for (final Specification<?> spec : compositeSpecification.specifications) {
248 if (spec instanceof CompositeSpecification) {
249 final AbstractCompositeSpecification wrappedCompositeSpecification = (AbstractCompositeSpecification) spec;
250 if (!wrappedCompositeSpecification.isSimpleComposition()) {
251 return FALSE;
252 }
253 } else if (spec instanceof ParameterizedSpecification) {
254 return FALSE;
255 }
256 }
257 return TRUE;
258 }
259
260
261
262
263 protected static Specification createValueBoundSpecification(final RelationalOperator relationalOperator, final Object operandValue) {
264
265
266
267
268
269 switch (relationalOperator) {
270 case EQUAL:
271 return SpecificationFactory.equalTo(operandValue);
272
273 case NOT_EQUAL:
274 return SpecificationFactory.not(SpecificationFactory.equalTo(operandValue));
275
276 case LESS_THAN:
277 if (operandValue instanceof Comparable) {
278 return SpecificationFactory.lessThan((Comparable) operandValue);
279 } else {
280 throw new IllegalArgumentException("Cannot create a LessThanSpecification with non-Comparable value");
281 }
282
283 case LESS_THAN_OR_EQUAL:
284 if (operandValue instanceof Comparable) {
285 return SpecificationFactory.lessThanOrEqualTo((Comparable) operandValue);
286 } else {
287 throw new IllegalArgumentException("Cannot create a LessThanSpecification with non-Comparable value");
288 }
289
290 case GREATER_THAN:
291 if (operandValue instanceof Comparable) {
292 return SpecificationFactory.greaterThan((Comparable) operandValue);
293 } else {
294 throw new IllegalArgumentException("Cannot create a LessThanSpecification with non-Comparable value");
295 }
296
297 case GREATER_THAN_OR_EQUAL:
298 if (operandValue instanceof Comparable) {
299 return SpecificationFactory.greaterThanOrEqualTo((Comparable) operandValue);
300 } else {
301 throw new IllegalArgumentException("Cannot create a LessThanSpecification with non-Comparable value");
302 }
303 }
304 throw new NotImplementedException();
305 }
306
307
308 protected static int getNumberOfLevelsOfNegations(final JointDenialSpecification jointDenialSpecification, int levelIndex) {
309 final Set<Specification<?>> subSpecs = jointDenialSpecification.specifications;
310 if (subSpecs.size() != 1) {
311 throw new IllegalStateException();
312 }
313 final Specification subSpec = subSpecs.iterator().next();
314 ++levelIndex;
315 if (subSpec instanceof JointDenialSpecification) {
316 return getNumberOfLevelsOfNegations((JointDenialSpecification) subSpec, levelIndex);
317 } else {
318 return levelIndex;
319 }
320 }
321
322
323 protected static <V> Specification<V> getNegatedSpecification(final JointDenialSpecification<V> jointDenialSpecification) {
324 final Set<Specification<? super V>> subSpecs = jointDenialSpecification.specifications;
325 final Specification<? super V> subSpec = subSpecs.iterator().next();
326 if (subSpecs.size() != 1) {
327 throw new IllegalStateException();
328 }
329 if (subSpec instanceof JointDenialSpecification) {
330 return (Specification<V>) getNegatedSpecification((JointDenialSpecification<? super V>) subSpec);
331 } else {
332 return (Specification<V>) subSpec;
333 }
334 }
335
336
337 protected static boolean isOddNumber(final int number) {
338 return number % 2 != 0;
339 }
340
341
342 @Override
343 public String toString() {
344 return new ReflectionToStringBuilder(this).toString();
345 }
346 }