001 package org.springframework.rules.constraint.property;
002
003 import org.springframework.binding.PropertyAccessStrategy;
004 import org.springframework.rules.constraint.IfTrue;
005 import org.springframework.rules.reporting.TypeResolvable;
006 import org.springframework.util.Assert;
007
008 /**
009 * <p>
010 * Provides a way to trigger rules for propertyB when propertyA satisfies a
011 * certain condition:
012 * </p>
013 *
014 * <pre>
015 * if (propertyA satisfies the conditional constraint)
016 * {
017 * check the rules for propertyB
018 * }
019 * </pre>
020 *
021 * with an optional part:
022 *
023 * <pre>
024 * else
025 * {
026 * check the rules for propertyC
027 * }
028 * </pre>
029 *
030 * <p>
031 * More complex situations are possible by using compound constraints which
032 * leverages the previous to:
033 * </p>
034 *
035 * <pre>
036 * if (constraint(propertyA, propertyB,...) == true)
037 * {
038 * checkConstraint(property1, property2,...);
039 * }
040 * \\ optional part
041 * else
042 * {
043 * checkConstraint(propertyX, propertyY,...);
044 * }
045 * </pre>
046 *
047 * <p>
048 * This class can be compared to the {@link IfTrue} class: it applies the same
049 * pattern but on different <b>properties</b> instead of on a <b>property value</b>.
050 * </p>
051 *
052 * @author jh
053 *
054 */
055 public class ConditionalPropertyConstraint extends AbstractPropertyConstraint implements TypeResolvable {
056
057 /** The condition which triggers further rules to be checked. */
058 private final PropertyConstraint ifConstraint;
059
060 /** The constraint to be checked when the condition is satisfied. */
061 private final PropertyConstraint thenConstraint;
062
063 /** The constraint to be checked when the condition is <b>NOT</b> satisfied. */
064 private final PropertyConstraint elseConstraint;
065
066 /** Type used to fetch message. */
067 private String type;
068
069 /**
070 * @see #ConditionalPropertyConstraint(PropertyConstraint, PropertyConstraint, String)
071 */
072 public ConditionalPropertyConstraint(PropertyConstraint ifConstraint, PropertyConstraint thenConstraint) {
073 this(ifConstraint, thenConstraint, null, null);
074 }
075
076 /**
077 * Create a constraint which simulates the if...then pattern applied
078 * on separate properties.
079 *
080 * @param ifConstraint the PropertyConstraint that triggers the test
081 * (satisfying a certain condition).
082 * @param thenConstraint the PropertyConstraint to test in the specified
083 * condition.
084 */
085 public ConditionalPropertyConstraint(PropertyConstraint ifConstraint, PropertyConstraint thenConstraint, String type) {
086 this(ifConstraint, thenConstraint, null, type);
087 }
088
089 /**
090 * @see #ConditionalPropertyConstraint(PropertyConstraint, PropertyConstraint, PropertyConstraint, String)
091 */
092 public ConditionalPropertyConstraint(PropertyConstraint ifConstraint, PropertyConstraint thenConstraint,
093 PropertyConstraint elseConstraint) {
094 this(ifConstraint, thenConstraint, elseConstraint, null);
095 }
096 /**
097 * Create a constraint which simulates the if...then...else pattern applied
098 * on separate properties.
099 *
100 * @param ifConstraint the PropertyConstraint that triggers the test
101 * (satisfying a certain condition).
102 * @param thenConstraint the PropertyConstraint to test in the specified
103 * condition.
104 * @param elseConstraint the PropertyConstraint to test if the condition is
105 * <b>NOT</b> satisfied. May be <code>null</code>.
106 * @param type the messageCode used to fetch the message.
107 */
108 public ConditionalPropertyConstraint(PropertyConstraint ifConstraint, PropertyConstraint thenConstraint,
109 PropertyConstraint elseConstraint, String type) {
110 super(ifConstraint.getPropertyName());
111 Assert.notNull(ifConstraint);
112 Assert.notNull(thenConstraint);
113 this.ifConstraint = ifConstraint;
114 this.thenConstraint = thenConstraint;
115 this.elseConstraint = elseConstraint;
116 this.type = type;
117 }
118
119 public boolean isCompoundRule() {
120 return true;
121 }
122
123 public boolean isDependentOn(String propertyName) {
124 if (elseConstraint == null)
125 return ifConstraint.isDependentOn(propertyName) || thenConstraint.isDependentOn(propertyName);
126
127 return ifConstraint.isDependentOn(propertyName) || thenConstraint.isDependentOn(propertyName)
128 || elseConstraint.isDependentOn(propertyName);
129 }
130
131 protected boolean test(PropertyAccessStrategy domainObjectAccessStrategy) {
132 if (ifConstraint.test(domainObjectAccessStrategy))
133 return thenConstraint.test(domainObjectAccessStrategy);
134 if (elseConstraint != null)
135 return elseConstraint.test(domainObjectAccessStrategy);
136
137 return true;
138 }
139
140 public String getType() {
141 return type;
142 }
143
144 public void setType(String type) {
145 this.type = type;
146 }
147 }