001 /*
002 * Copyright 2002-2004 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package org.springframework.rules.factory;
017
018 import java.util.Comparator;
019 import java.util.Set;
020
021 import org.springframework.rules.closure.Closure;
022 import org.springframework.rules.constraint.Constraint;
023 import org.springframework.rules.closure.support.AlgorithmsAccessor;
024 import org.springframework.rules.closure.BinaryConstraint;
025 import org.springframework.rules.constraint.*;
026 import org.springframework.rules.constraint.Like.LikeType;
027 import org.springframework.rules.constraint.property.CompoundPropertyConstraint;
028 import org.springframework.rules.constraint.property.ConditionalPropertyConstraint;
029 import org.springframework.rules.constraint.property.NegatedPropertyConstraint;
030 import org.springframework.rules.constraint.property.ParameterizedPropertyConstraint;
031 import org.springframework.rules.constraint.property.PropertiesConstraint;
032 import org.springframework.rules.constraint.property.PropertyConstraint;
033 import org.springframework.rules.constraint.property.PropertyValueConstraint;
034 import org.springframework.rules.constraint.property.UniquePropertyValueConstraint;
035 import org.springframework.util.Assert;
036 import org.springframework.util.ObjectUtils;
037
038 /**
039 * A factory for easing the construction and composition of constraints.
040 *
041 * @author Keith Donald
042 */
043 public class Constraints extends AlgorithmsAccessor {
044
045 private static Constraints INSTANCE = new Constraints();
046
047 public Constraints() {
048
049 }
050
051 public static Constraints instance() {
052 return INSTANCE;
053 }
054
055 public static void load(Constraints sharedInstance) {
056 Assert.notNull(sharedInstance, "The global constraints factory cannot be null");
057 INSTANCE = sharedInstance;
058 }
059
060 /**
061 * Bind the specified parameter to the second argument of the
062 * <code>BinaryConstraint</code>. The result is a <code>Constraint</code>
063 * which will test a single variable argument against the constant
064 * parameter.
065 *
066 * @param constraint the binary constraint to bind to
067 * @param parameter the parameter value (constant)
068 * @return The constraint
069 */
070 public Constraint bind(BinaryConstraint constraint, Object parameter) {
071 return new ParameterizedBinaryConstraint(constraint, parameter);
072 }
073
074 /**
075 * Bind the specified <code>int</code> parameter to the second argument of
076 * the <code>BinaryConstraint</code>. The result is a
077 * <code>Constraint</code> which will test a single variable argument
078 * against the constant <code>int</code> parameter.
079 *
080 * @param constraint the binary constraint to bind to
081 * @param parameter the <code>int</code> parameter value (constant)
082 * @return The constraint
083 */
084 public Constraint bind(BinaryConstraint constraint, int parameter) {
085 return new ParameterizedBinaryConstraint(constraint, parameter);
086 }
087
088 /**
089 * Bind the specified <code>float</code> parameter to the second argument
090 * of the <code>BinaryConstraint</code>. The result is a
091 * <code>Constraint</code> which will test a single variable argument
092 * against the constant <code>float</code> parameter.
093 *
094 * @param constraint the binary constraint to bind to
095 * @param parameter the <code>float</code> parameter value (constant)
096 * @return The constraint
097 */
098 public Constraint bind(BinaryConstraint constraint, float parameter) {
099 return new ParameterizedBinaryConstraint(constraint, parameter);
100 }
101
102 /**
103 * Bind the specified <code>double</code> parameter to the second argument
104 * of the <code>BinaryConstraint</code>. The result is a
105 * <code>Constraint</code> which will test a single variable argument
106 * against the constant <code>double</code> parameter.
107 *
108 * @param constraint the binary constraint to bind to
109 * @param parameter the <code>double</code> parameter value (constant)
110 * @return The constraint
111 */
112 public Constraint bind(BinaryConstraint constraint, double parameter) {
113 return new ParameterizedBinaryConstraint(constraint, parameter);
114 }
115
116 /**
117 * Bind the specified <code>boolean</code> parameter to the second
118 * argument of the <code>BinaryConstraint</code>. The result is a
119 * <code>Constraint</code> which will test a single variable argument
120 * against the constant <code>boolean</code> parameter.
121 *
122 * @param constraint the binary constraint to bind to
123 * @param parameter the <code>boolean</code> parameter value (constant)
124 * @return The constraint
125 */
126 public Constraint bind(BinaryConstraint constraint, boolean parameter) {
127 return new ParameterizedBinaryConstraint(constraint, parameter);
128 }
129
130 /**
131 * Attaches a constraint that tests the result returned by evaluating the
132 * specified closure. This effectively attaches a constraint on the closure
133 * return value.
134 *
135 * @param closure the closure
136 * @param constraint the constraint to test the closure result
137 * @return The testing constraint, which on the call to test(o) first
138 * evaluates 'o' using the closure and then tests the result.
139 */
140 public Constraint testResultOf(Closure closure, Constraint constraint) {
141 return new ClosureResultConstraint(closure, constraint);
142 }
143
144 public Constraint eq(Object value) {
145 return EqualTo.value(value);
146 }
147
148 public Constraint eq(int value) {
149 return eq(new Integer(value));
150 }
151
152 public Constraint eq(Object value, Comparator comparator) {
153 return EqualTo.value(value, comparator);
154 }
155
156 public Constraint gt(Comparable value) {
157 return GreaterThan.value(value);
158 }
159
160 public Constraint gt(Object value, Comparator comparator) {
161 return GreaterThan.value(value, comparator);
162 }
163
164 public Constraint gt(int value) {
165 return gt(new Integer(value));
166 }
167
168 public Constraint gt(long value) {
169 return gt(new Long(value));
170 }
171
172 public Constraint gt(float value) {
173 return gt(new Float(value));
174 }
175
176 public Constraint gt(double value) {
177 return gt(new Double(value));
178 }
179
180 public Constraint gte(Comparable value) {
181 return GreaterThanEqualTo.value(value);
182 }
183
184 public Constraint gte(Object value, Comparator comparator) {
185 return GreaterThanEqualTo.value(value, comparator);
186 }
187
188 public Constraint gte(int value) {
189 return gte(new Integer(value));
190 }
191
192 public Constraint gte(long value) {
193 return gte(new Long(value));
194 }
195
196 public Constraint gte(float value) {
197 return gte(new Float(value));
198 }
199
200 public Constraint gte(double value) {
201 return gte(new Double(value));
202 }
203
204 public Constraint lt(Comparable value) {
205 return LessThan.value(value);
206 }
207
208 public Constraint lt(Comparable value, Comparator comparator) {
209 return LessThan.value(value, comparator);
210 }
211
212 public Constraint lt(int value) {
213 return lt(new Integer(value));
214 }
215
216 public Constraint lt(long value) {
217 return lt(new Long(value));
218 }
219
220 public Constraint lt(float value) {
221 return lt(new Float(value));
222 }
223
224 public Constraint lt(double value) {
225 return lt(new Double(value));
226 }
227
228 public Constraint lte(Comparable value) {
229 return LessThanEqualTo.value(value);
230 }
231
232 public Constraint lte(Object value, Comparator comparator) {
233 return LessThanEqualTo.value(value, comparator);
234 }
235
236 public Constraint lte(int value) {
237 return lte(new Integer(value));
238 }
239
240 public Constraint lte(long value) {
241 return lte(new Long(value));
242 }
243
244 public Constraint lte(float value) {
245 return lte(new Float(value));
246 }
247
248 public Constraint lte(double value) {
249 return lte(new Double(value));
250 }
251
252 public Constraint range(Comparable min, Comparable max) {
253 return new Range(min, max);
254 }
255
256 public Constraint range(Comparable min, Comparable max, boolean inclusive) {
257 return new Range(min, max, inclusive);
258 }
259
260 public Constraint range(Object min, Object max, Comparator comparator) {
261 return new Range(min, max, comparator);
262 }
263
264 public Constraint range(Object min, Object max, Comparator comparator, boolean inclusive) {
265 return new Range(min, max, comparator, inclusive);
266 }
267
268 public Constraint range(int min, int max) {
269 return new Range(min, max);
270 }
271
272 public Constraint range(long min, long max) {
273 return new Range(min, max);
274 }
275
276 public Constraint range(float min, float max) {
277 return new Range(min, max);
278 }
279
280 public Constraint range(double min, double max) {
281 return new Range(min, max);
282 }
283
284 public Constraint present() {
285 return Required.present();
286 }
287
288 /**
289 * Returns a required constraint.
290 *
291 * @return The required constraint instance.
292 */
293 public Constraint required() {
294 return Required.instance();
295 }
296
297 public Constraint ifTrue(Constraint constraint, Constraint mustAlsoBeTrue) {
298 return new IfTrue(constraint, mustAlsoBeTrue);
299 }
300
301 public Constraint ifTrue(Constraint constraint, Constraint mustAlsoBeTrue, Constraint elseMustAlsoBeTrue) {
302 return new IfTrue(constraint, mustAlsoBeTrue, elseMustAlsoBeTrue);
303 }
304
305 public Constraint ifTrue(Constraint constraint, Constraint mustAlsoBeTrue, String type) {
306 return new IfTrue(constraint, mustAlsoBeTrue, type);
307 }
308
309 public Constraint ifTrue(Constraint constraint, Constraint mustAlsoBeTrue, Constraint elseMustAlsoBeTrue, String type) {
310 return new IfTrue(constraint, mustAlsoBeTrue, elseMustAlsoBeTrue, type);
311 }
312
313 /**
314 * Returns a ConditionalPropertyConstraint: one property will trigger the
315 * validation of another.
316 *
317 * @see ConditionalPropertyConstraint
318 */
319 public PropertyConstraint ifTrue(PropertyConstraint ifConstraint, PropertyConstraint thenConstraint) {
320 return new ConditionalPropertyConstraint(ifConstraint, thenConstraint);
321 }
322
323 /**
324 * Returns a ConditionalPropertyConstraint: one property will trigger the
325 * validation of another.
326 *
327 * @see ConditionalPropertyConstraint
328 */
329 public PropertyConstraint ifTrue(PropertyConstraint ifConstraint, PropertyConstraint thenConstraint, String type) {
330 return new ConditionalPropertyConstraint(ifConstraint, thenConstraint, type);
331 }
332
333 /**
334 * Returns a ConditionalPropertyConstraint: one property will trigger the
335 * validation of another.
336 *
337 * @see ConditionalPropertyConstraint
338 */
339 public PropertyConstraint ifTrue(PropertyConstraint ifConstraint, PropertyConstraint thenConstraint,
340 PropertyConstraint elseConstraint) {
341 return new ConditionalPropertyConstraint(ifConstraint, thenConstraint, elseConstraint);
342 }
343
344 /**
345 * Returns a ConditionalPropertyConstraint: one property will trigger the
346 * validation of another.
347 *
348 * @see ConditionalPropertyConstraint
349 */
350 public PropertyConstraint ifTrue(PropertyConstraint ifConstraint, PropertyConstraint thenConstraint,
351 PropertyConstraint elseConstraint, String type) {
352 return new ConditionalPropertyConstraint(ifConstraint, thenConstraint, elseConstraint, type);
353 }
354
355 /**
356 * Returns a ConditionalPropertyConstraint: one property will trigger the
357 * validation of another.
358 *
359 * @see ConditionalPropertyConstraint
360 */
361 public PropertyConstraint ifTrue(PropertyConstraint ifConstraint, PropertyConstraint[] thenConstraints) {
362 return new ConditionalPropertyConstraint(ifConstraint, new CompoundPropertyConstraint(new And(thenConstraints)));
363 }
364
365 /**
366 * Returns a ConditionalPropertyConstraint: one property will trigger the
367 * validation of another.
368 *
369 * @see ConditionalPropertyConstraint
370 */
371 public PropertyConstraint ifTrue(PropertyConstraint ifConstraint, PropertyConstraint[] thenConstraints, String type) {
372 return new ConditionalPropertyConstraint(ifConstraint, new CompoundPropertyConstraint(new And(thenConstraints)), type);
373 }
374
375 /**
376 * Returns a ConditionalPropertyConstraint: one property will trigger the
377 * validation of another.
378 *
379 * @see ConditionalPropertyConstraint
380 */
381 public PropertyConstraint ifTrue(PropertyConstraint ifConstraint, PropertyConstraint[] thenConstraints,
382 PropertyConstraint[] elseConstraints) {
383 return new ConditionalPropertyConstraint(ifConstraint,
384 new CompoundPropertyConstraint(new And(thenConstraints)), new CompoundPropertyConstraint(new And(
385 elseConstraints)));
386 }
387
388 /**
389 * Returns a ConditionalPropertyConstraint: one property will trigger the
390 * validation of another.
391 *
392 * @see ConditionalPropertyConstraint
393 */
394 public PropertyConstraint ifTrue(PropertyConstraint ifConstraint, PropertyConstraint[] thenConstraints,
395 PropertyConstraint[] elseConstraints, String type) {
396 return new ConditionalPropertyConstraint(ifConstraint,
397 new CompoundPropertyConstraint(new And(thenConstraints)), new CompoundPropertyConstraint(new And(
398 elseConstraints)), type);
399 }
400
401 /**
402 * Returns a maxlength constraint.
403 *
404 * @param maxLength The maximum length in characters.
405 * @return The configured maxlength constraint.
406 */
407 public Constraint maxLength(int maxLength) {
408 return new StringLengthConstraint(maxLength);
409 }
410
411 /**
412 * Returns a minlength constraint.
413 *
414 * @param minLength The minimum length in characters.
415 * @return The configured minlength constraint.
416 */
417 public Constraint minLength(int minLength) {
418 return new StringLengthConstraint(RelationalOperator.GREATER_THAN_EQUAL_TO, minLength);
419 }
420
421 /**
422 * Returns a 'like' constraint.
423 *
424 * @param encodedLikeString the likeString
425 * @return The Like constraint.
426 */
427 public Constraint like(String encodedLikeString) {
428 return new Like(encodedLikeString);
429 }
430
431 /**
432 * Creates a constraint backed by a regular expression.
433 *
434 * @param regexp The regular expression string.
435 * @return The constraint.
436 */
437 public Constraint regexp(String regexp) {
438 return new RegexpConstraint(regexp);
439 }
440
441 /**
442 * Creates a constraint backed by a regular expression, with a type for
443 * reporting.
444 *
445 * @param regexp The regular expression string.
446 * @return The constraint.
447 */
448 public Constraint regexp(String regexp, String type) {
449 RegexpConstraint c = new RegexpConstraint(regexp);
450 c.setType(type);
451 return c;
452 }
453
454 /**
455 * Returns a constraint whose test is determined by a boolean method on a
456 * target object.
457 *
458 * @param targetObject The targetObject
459 * @param methodName The method name
460 * @return The constraint.
461 */
462 public Constraint method(Object target, String methodName, String constraintType) {
463 return new MethodInvokingConstraint(target, methodName, constraintType);
464 }
465
466 /**
467 * Returns a 'in' group (or set) constraint.
468 *
469 * @param group the group items
470 * @return The InGroup constraint
471 */
472 public Constraint inGroup(Set group) {
473 return new InGroup(group);
474 }
475
476 /**
477 * Returns a 'in' group (or set) constraint.
478 *
479 * @param group the group items
480 * @return The InGroup constraint.
481 */
482 public Constraint inGroup(Object[] group) {
483 return new InGroup(group);
484 }
485
486 /**
487 * Returns a 'in' group (or set) constraint.
488 *
489 * @param group the group items
490 * @return The InGroup constraint.
491 */
492 public Constraint inGroup(int[] group) {
493 return inGroup(ObjectUtils.toObjectArray(group));
494 }
495
496 /**
497 * AND two constraints.
498 *
499 * @param constraint1 the first constraint
500 * @param constraint2 the second constraint
501 * @return The compound AND constraint
502 */
503 public And and(Constraint constraint1, Constraint constraint2) {
504 return new And(constraint1, constraint2);
505 }
506
507 /**
508 * Return the conjunction (all constraint) for all constraints.
509 *
510 * @param constraints the constraints
511 * @return The compound AND constraint
512 */
513 public And all(Constraint[] constraints) {
514 return new And(constraints);
515 }
516
517 /**
518 * Returns a new, empty conjunction prototype, capable of composing
519 * individual constraints where 'ALL' must test true.
520 *
521 * @return the UnaryAnd
522 */
523 public And conjunction() {
524 return new And();
525 }
526
527 /**
528 * OR two constraints.
529 *
530 * @param constraint1 the first constraint
531 * @param constraint2 the second constraint
532 * @return The compound OR constraint
533 */
534 public Or or(Constraint constraint1, Constraint constraint2) {
535 return new Or(constraint1, constraint2);
536 }
537
538 /**
539 * Return the disjunction (any constraint) for all constraints.
540 *
541 * @param constraints the constraints
542 * @return The compound AND constraint
543 */
544 public Or any(Constraint[] constraints) {
545 return new Or(constraints);
546 }
547
548 /**
549 * Returns a new, empty disjunction prototype, capable of composing
550 * individual constraints where 'ANY' must test true.
551 *
552 * @return the UnaryOr
553 */
554 public Or disjunction() {
555 return new Or();
556 }
557
558 /**
559 * Returns a new, empty exclusive disjunction prototype, capable of composing
560 * individual constraints where only one must test true.
561 *
562 * @return the UnaryXOr
563 */
564 public XOr exclusiveDisjunction() {
565 return new XOr();
566 }
567
568 /**
569 * Negate the specified constraint.
570 *
571 * @param constraint The constraint to negate
572 * @return The negated constraint.
573 */
574 public Constraint not(Constraint constraint) {
575 if (!(constraint instanceof Not))
576 return new Not(constraint);
577
578 return ((Not)constraint).getConstraint();
579 }
580
581 /**
582 * Attach a value constraint for the provided bean property.
583 *
584 * @param propertyName the bean property name
585 * @param valueConstraint the value constraint
586 * @return The bean property expression that tests the constraint
587 */
588 public PropertyConstraint value(String propertyName, Constraint valueConstraint) {
589 return new PropertyValueConstraint(propertyName, valueConstraint);
590 }
591
592 /**
593 * Returns a present bean property expression.
594 *
595 * @return The present constraint instance.
596 */
597 public PropertyConstraint present(String propertyName) {
598 return value(propertyName, present());
599 }
600
601 /**
602 * Returns a required bean property expression.
603 *
604 * @return The required constraint instance.
605 */
606 public PropertyConstraint required(String property) {
607 return value(property, required());
608 }
609
610 /**
611 * Return a 'like' constraint applied as a value constraint to the provided
612 * property.
613 *
614 * @param property The property to constrain
615 * @param likeType The like type
616 * @param value The like string value to match
617 * @return The Like constraint
618 */
619 public PropertyConstraint like(String property, LikeType likeType, String value) {
620 return value(property, new Like(likeType, value));
621 }
622
623 /**
624 * Returns a 'in' group (or set) constraint appled to the provided property.
625 *
626 * @param propertyName the property
627 * @param group the group items
628 * @return The InGroup constraint.
629 */
630 public PropertyConstraint inGroup(String propertyName, Object[] group) {
631 return value(propertyName, new InGroup(group));
632 }
633
634 /**
635 * Apply an "all" value constraint to the provided bean property.
636 *
637 * @param propertyName The bean property name
638 * @param constraints The constraints that form a all conjunction
639 * @return
640 */
641 public PropertyConstraint all(String propertyName, Constraint[] constraints) {
642 return value(propertyName, all(constraints));
643 }
644
645 /**
646 * Apply an "any" value constraint to the provided bean property.
647 *
648 * @param propertyName The bean property name
649 * @param constraints The constraints that form a all disjunction
650 * @return
651 */
652 public PropertyConstraint any(String propertyName, Constraint[] constraints) {
653 return value(propertyName, any(constraints));
654 }
655
656 /**
657 * Negate a bean property expression.
658 *
659 * @param e the expression to negate
660 * @return The negated expression
661 */
662 public PropertyConstraint not(PropertyConstraint e) {
663 return new NegatedPropertyConstraint(e);
664 }
665
666 public PropertyConstraint valueProperty(String propertyName, BinaryConstraint constraint, Object value) {
667 return new ParameterizedPropertyConstraint(propertyName, constraint, value);
668 }
669
670 /**
671 * Apply a "equal to" constraint to a bean property.
672 *
673 * @param propertyName The first property
674 * @param propertyValue The constraint value
675 * @return The constraint
676 */
677 public PropertyConstraint eq(String propertyName, Object propertyValue) {
678 return new ParameterizedPropertyConstraint(propertyName, eq(propertyValue));
679 }
680
681 /**
682 * Apply a "equal to" constraint to a bean property.
683 *
684 * @param propertyName The first property
685 * @param propertyValue The constraint value
686 * @param comparator the comparator to use while comparing the values
687 * @return The constraint
688 *
689 * @since 0.3.0
690 */
691 public PropertyConstraint eq(String propertyName, Object propertyValue, Comparator comparator) {
692 return new ParameterizedPropertyConstraint(propertyName, eq(propertyValue, comparator));
693 }
694
695 /**
696 * Apply a "greater than" constraint to a bean property.
697 *
698 * @param propertyName The first property
699 * @param propertyValue The constraint value
700 * @return The constraint
701 */
702 public PropertyConstraint gt(String propertyName, Comparable propertyValue) {
703 return new ParameterizedPropertyConstraint(propertyName, gt(propertyValue));
704 }
705
706 /**
707 * Apply a "greater than equal to" constraint to a bean property.
708 *
709 * @param propertyName The first property
710 * @param propertyValue The constraint value
711 * @return The constraint
712 */
713 public PropertyConstraint gte(String propertyName, Comparable propertyValue) {
714 return new ParameterizedPropertyConstraint(propertyName, gte(propertyValue));
715 }
716
717 /**
718 * Apply a "less than" constraint to a bean property.
719 *
720 * @param propertyName The first property
721 * @param propertyValue The constraint value
722 * @return The constraint
723 */
724 public PropertyConstraint lt(String propertyName, Comparable propertyValue) {
725 return new ParameterizedPropertyConstraint(propertyName, lt(propertyValue));
726 }
727
728 /**
729 * Apply a "less than equal to" constraint to a bean property.
730 *
731 * @param propertyName The first property
732 * @param propertyValue The constraint value
733 * @return The constraint
734 */
735 public PropertyConstraint lte(String propertyName, Comparable propertyValue) {
736 return new ParameterizedPropertyConstraint(propertyName, lte(propertyValue));
737 }
738
739 public PropertyConstraint valueProperties(String propertyName, BinaryConstraint constraint, String otherPropertyName) {
740 return new PropertiesConstraint(propertyName, constraint, otherPropertyName);
741 }
742
743 /**
744 * Apply a "equal to" constraint to two bean properties.
745 *
746 * @param propertyName The first property
747 * @param otherPropertyName The other property
748 * @param comparator the comparator to use while comparing the values
749 * @return The constraint
750 *
751 * @since 0.3.0
752 */
753 public PropertyConstraint eqProperty(String propertyName, String otherPropertyName, Comparator comparator) {
754 return valueProperties(propertyName, EqualTo.instance(comparator), otherPropertyName);
755 }
756
757 /**
758 * Apply a "greater than" constraint to two properties
759 *
760 * @param propertyName The first property
761 * @param otherPropertyName The other property
762 * @param comparator the comparator to use while comparing the values
763 * @return The constraint
764 *
765 * @since 0.3.0
766 */
767 public PropertyConstraint gtProperty(String propertyName, String otherPropertyName, Comparator comparator) {
768 return valueProperties(propertyName, GreaterThan.instance(comparator), otherPropertyName);
769 }
770
771 /**
772 * Apply a "greater than or equal to" constraint to two properties.
773 *
774 * @param propertyName The first property
775 * @param otherPropertyName The other property
776 * @param comparator the comparator to use while comparing the values
777 * @return The constraint
778 *
779 * @since 0.3.0
780 */
781 public PropertyConstraint gteProperty(String propertyName, String otherPropertyName, Comparator comparator) {
782 return valueProperties(propertyName, GreaterThanEqualTo.instance(comparator), otherPropertyName);
783 }
784
785 /**
786 * Apply a "less than" constraint to two properties.
787 *
788 * @param propertyName The first property
789 * @param otherPropertyName The other property
790 * @param comparator the comparator to use while comparing the values
791 * @return The constraint
792 *
793 * @since 0.3.0
794 */
795 public PropertyConstraint ltProperty(String propertyName, String otherPropertyName, Comparator comparator) {
796 return valueProperties(propertyName, LessThan.instance(comparator), otherPropertyName);
797 }
798
799 /**
800 * Apply a "less than or equal to" constraint to two properties.
801 *
802 * @param propertyName The first property
803 * @param otherPropertyName The other property
804 * @param comparator the comparator to use while comparing the values
805 * @return The constraint
806 *
807 * @since 0.3.0
808 */
809 public PropertyConstraint lteProperty(String propertyName, String otherPropertyName, Comparator comparator) {
810 return valueProperties(propertyName, LessThanEqualTo.instance(comparator), otherPropertyName);
811 }
812
813 /**
814 * Apply a inclusive "range" constraint to a bean property.
815 *
816 * @param propertyName the property with the range constraint.
817 * @param min the low edge of the range
818 * @param max the high edge of the range
819 * @param comparator the comparator to use while comparing the values
820 * @return The range constraint constraint
821 *
822 * @since 0.3.0
823 */
824 public PropertyConstraint inRange(String propertyName, Object min, Object max, Comparator comparator) {
825 return value(propertyName, range(min, max, comparator));
826 }
827
828 /**
829 * Apply a inclusive "range" constraint between two other properties to a
830 * bean property.
831 *
832 * @param propertyName the property with the range constraint.
833 * @param minPropertyName the low edge of the range
834 * @param maxPropertyName the high edge of the range
835 * @param comparator the comparator to use while comparing the values
836 * @return The range constraint constraint
837 *
838 * @since 0.3.0
839 */
840 public PropertyConstraint inRangeProperties(String propertyName, String minPropertyName, String maxPropertyName, Comparator comparator) {
841 Constraint min = gteProperty(propertyName, minPropertyName, comparator);
842 Constraint max = lteProperty(propertyName, maxPropertyName, comparator);
843 return new CompoundPropertyConstraint(new And(min, max));
844 }
845
846 /**
847 * Apply a "equal to" constraint to two bean properties.
848 *
849 * @param propertyName The first property
850 * @param otherPropertyName The other property
851 * @return The constraint
852 */
853 public PropertyConstraint eqProperty(String propertyName, String otherPropertyName) {
854 return valueProperties(propertyName, EqualTo.instance(), otherPropertyName);
855 }
856
857 /**
858 * Apply a "greater than" constraint to two properties
859 *
860 * @param propertyName The first property
861 * @param otherPropertyName The other property
862 * @return The constraint
863 */
864 public PropertyConstraint gtProperty(String propertyName, String otherPropertyName) {
865 return valueProperties(propertyName, GreaterThan.instance(), otherPropertyName);
866 }
867
868 /**
869 * Apply a "greater than or equal to" constraint to two properties.
870 *
871 * @param propertyName The first property
872 * @param otherPropertyName The other property
873 * @return The constraint
874 */
875 public PropertyConstraint gteProperty(String propertyName, String otherPropertyName) {
876 return valueProperties(propertyName, GreaterThanEqualTo.instance(), otherPropertyName);
877 }
878
879 /**
880 * Apply a "less than" constraint to two properties.
881 *
882 * @param propertyName The first property
883 * @param otherPropertyName The other property
884 * @return The constraint
885 */
886 public PropertyConstraint ltProperty(String propertyName, String otherPropertyName) {
887 return valueProperties(propertyName, LessThan.instance(), otherPropertyName);
888 }
889
890 /**
891 * Apply a "less than or equal to" constraint to two properties.
892 *
893 * @param propertyName The first property
894 * @param otherPropertyName The other property
895 * @return The constraint
896 */
897 public PropertyConstraint lteProperty(String propertyName, String otherPropertyName) {
898 return valueProperties(propertyName, LessThanEqualTo.instance(), otherPropertyName);
899 }
900
901 /**
902 * Apply a inclusive "range" constraint to a bean property.
903 *
904 * @param propertyName the property with the range constraint.
905 * @param min the low edge of the range
906 * @param max the high edge of the range
907 * @return The range constraint constraint
908 */
909 public PropertyConstraint inRange(String propertyName, Comparable min, Comparable max) {
910 return value(propertyName, range(min, max));
911 }
912
913 /**
914 * Apply a inclusive "range" constraint between two other properties to a
915 * bean property.
916 *
917 * @param propertyName the property with the range constraint.
918 * @param minPropertyName the low edge of the range
919 * @param maxPropertyName the high edge of the range
920 * @return The range constraint constraint
921 */
922 public PropertyConstraint inRangeProperties(String propertyName, String minPropertyName, String maxPropertyName) {
923 Constraint min = gteProperty(propertyName, minPropertyName);
924 Constraint max = lteProperty(propertyName, maxPropertyName);
925 return new CompoundPropertyConstraint(new And(min, max));
926 }
927
928 /**
929 * Create a unique property value constraint that will test a collection of
930 * domain objects, returning true if all objects have unique values for the
931 * provided propertyName.
932 * @param propertyName The property name
933 * @return The constraint
934 */
935 public PropertyConstraint unique(String propertyName) {
936 return new UniquePropertyValueConstraint(propertyName);
937 }
938 }