1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.sovt.impl;
29
30 import org.apache.commons.beanutils.MethodUtils;
31 import org.apache.commons.beanutils.PropertyUtils;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.sovt.*;
35
36 import java.lang.reflect.InvocationTargetException;
37 import java.util.ArrayList;
38 import java.util.Iterator;
39 import java.util.List;
40
41 /***
42 * This class is used to validate properties of JavaBean objects. It extracts
43 * property of JavaBean, forwards it to sub-validators/transformers/inspectors
44 * and then sets this property again if necessary (only for transform/inspect).
45 *
46 * @author Vilmantas Baranauskas (vilmantas_baranauskas@yahoo.com)
47 */
48 public class PropertySelector
49 implements Inspector, Transformer, Validator, Cloneable {
50 private static final Log log = LogFactory.getLog(PropertySelector.class);
51
52
53 /***
54 * List of validators/transformers/inspectors in this group.
55 */
56 private List elements = new ArrayList();
57
58 /***
59 * Name of the property to work on.
60 */
61 private String propertyName;
62
63
64 /***
65 * Creates instance of PropertySelector. The instance can be registered as
66 * any of: Inspector, Transformer, Validator.
67 */
68 public PropertySelector() {
69 }
70
71
72 /***
73 * Adds inspector to the group.
74 *
75 * @param inspector Inspector to add.
76 */
77 public void addInspector(Inspector inspector) {
78 elements.add(inspector);
79 }
80
81 /***
82 * Adds transformer to the group.
83 *
84 * @param transformer Transformer to add.
85 */
86 public void addTransformer(Transformer transformer) {
87 elements.add(transformer);
88 }
89
90 /***
91 * Adds validator to the group.
92 *
93 * @param validator Validator to add.
94 */
95 public void addValidator(Validator validator) {
96 elements.add(validator);
97 }
98
99 /***
100 * Performs a partly deep-cloning. New list of contained elements is created
101 * but elements themselfs are not cloned.
102 *
103 * @return clone of itself.
104 * @throws CloneNotSupportedException never.
105 */
106 public Object clone() throws CloneNotSupportedException {
107 PropertySelector inspector = (PropertySelector) super.clone();
108 inspector.elements = new ArrayList(elements);
109 return inspector;
110 }
111
112 /***
113 * Extracts specified property from the given JavaBean.
114 *
115 * @param object Source object.
116 * @param propertyName Property to extract.
117 * @return extracted property or null if there is no such property.
118 */
119 private static Object extractProperty(Object object, String propertyName) {
120 try {
121 return PropertyUtils.getProperty(object, propertyName);
122 } catch (IllegalAccessException e) {
123
124 } catch (InvocationTargetException e) {
125
126 } catch (NoSuchMethodException e) {
127
128 }
129
130
131 try {
132 return MethodUtils.invokeExactMethod(object, "get", propertyName);
133 } catch (NoSuchMethodException e) {
134 log.error("Cannot extract property [" + propertyName + "]", e);
135 } catch (IllegalAccessException e) {
136 log.error("Cannot extract property [" + propertyName + "]", e);
137 } catch (InvocationTargetException e) {
138 log.error("Cannot extract property [" + propertyName + "]", e);
139 }
140
141 return null;
142 }
143
144 /***
145 * Performs transformation and validation of given object. Transformers,
146 * validators and inspectors are invoked in the order they are registered.
147 *
148 * @param object Object to inspect.
149 * @param result Container for validation results.
150 * @return Transformed or completely new object which is also validated.
151 */
152 public Object inspect(Object object, ValidationResult result) {
153 result = new PrefixedValidationResult(result, propertyName);
154
155
156 Object property = extractProperty(object, propertyName);
157 Object originalProperty = property;
158
159 for (Iterator iterator = elements.iterator(); iterator.hasNext();) {
160 Object element = iterator.next();
161 if (element instanceof Inspector) {
162 Inspector inspector = (Inspector) element;
163 property = inspector.inspect(property, result);
164 } else if (element instanceof Transformer) {
165 Transformer transformer = (Transformer) element;
166 property = transformer.transform(property);
167 } else if (element instanceof Validator) {
168 Validator validator = (Validator) element;
169 validator.validate(property, result);
170 }
171 }
172
173
174
175 if (property != originalProperty) {
176 setProperty(object, propertyName, property);
177 }
178 return object;
179 }
180
181 /***
182 * Set the name of the property to work on. This can be specified as an
183 * attribute of a XML tag.
184 *
185 * @param property Name of the property to work on.
186 */
187 public void setName(String property) {
188 propertyName = property;
189 }
190
191 /***
192 * Set specified property on the given object.
193 *
194 * @param object Destination object.
195 * @param propertyName Name of the property to set.
196 * @param property Property value.
197 */
198 private static void setProperty(
199 Object object,
200 String propertyName,
201 Object property
202 ) {
203 try {
204 PropertyUtils.setProperty(object, propertyName, property);
205 return;
206 } catch (IllegalAccessException e) {
207
208 } catch (IllegalArgumentException e) {
209
210 } catch (InvocationTargetException e) {
211
212 } catch (NoSuchMethodException e) {
213
214 }
215
216
217 try {
218 MethodUtils.invokeExactMethod(
219 object,
220 "set",
221 new Object[] {
222 propertyName,
223 property
224 }
225 );
226 } catch (NoSuchMethodException e) {
227 log.error("Cannot set property [" + propertyName + "]");
228 } catch (IllegalAccessException e) {
229 log.error("Cannot set property [" + propertyName + "]", e);
230 } catch (InvocationTargetException e) {
231 log.error("Cannot set property [" + propertyName + "]", e);
232 }
233 }
234
235 /***
236 * Transforms given object. Given object can be modified or new object can
237 * be returned.
238 *
239 * @param object Object to transform.
240 * @return Transformed or completely new object.
241 */
242 public Object transform(Object object) {
243
244 Object property = extractProperty(object, propertyName);
245
246 for (Iterator iterator = elements.iterator(); iterator.hasNext();) {
247 Object element = iterator.next();
248 if (element instanceof Transformer) {
249 Transformer transformer = (Transformer) element;
250 property = transformer.transform(property);
251 }
252 }
253
254 setProperty(object, propertyName, property);
255 return object;
256 }
257
258 /***
259 * Implementation should validate given object and use result parameter to
260 * store stores validation result.
261 *
262 * @param object Object to validate
263 * @param result Container for validation results.
264 */
265 public void validate(Object object, ValidationResult result) {
266 result = new PrefixedValidationResult(result, propertyName);
267
268
269 Object property = extractProperty(object, propertyName);
270
271 for (Iterator iterator = elements.iterator(); iterator.hasNext();) {
272 Object element = iterator.next();
273 if (element instanceof Validator) {
274 Validator validator = (Validator) element;
275 validator.validate(property, result);
276 }
277 }
278 }
279
280 }