2009/05/20 - Apache Shale has been retired.
For more information, please explore the Attic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shale.validator.util;
19
20 import java.lang.reflect.Method;
21 import java.lang.reflect.Modifier;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Locale;
26 import java.util.Map;
27 import org.apache.commons.validator.Arg;
28 import org.apache.commons.validator.Field;
29 import org.apache.commons.validator.Form;
30 import org.apache.commons.validator.ValidatorAction;
31 import org.apache.commons.validator.ValidatorResources;
32
33 /***
34 * <p>Custom wrapper around a Commons Validator <code>ValidatorAction</code>
35 * that precalculates as many of the introspective lookup operations as
36 * possible. This ensures that runtime operation of the validator checks
37 * can proceed as quickly as possible.</p>
38 */
39 public final class ShaleValidatorAction {
40
41
42
43
44
45 /***
46 * <p>Create a new instance of ShaleValidatorAction that wraps the
47 * specified <code>ValidatorAction</code>.</p>
48 *
49 * @param resources <code>ValidatorResources</code> for this application
50 * @param action The <code>ValidatorAction</code> to be wrapped
51 *
52 * @exception IllegalArgumentException if configuration data is missing
53 * or incorrect
54 */
55 public ShaleValidatorAction(ValidatorResources resources,
56 ValidatorAction action) {
57
58 this.resources = resources;
59 this.action = action;
60 precalculate();
61
62 }
63
64
65
66
67
68 /***
69 * <p>The prefix for form names that correspond to validator types.</p>
70 */
71 private static final String FORM_NAME_PREFIX = "org.apache.shale.validator.";
72
73
74 /***
75 * <p>Map of the classes for primitive Java types, keyed by the Java
76 * keywords for the corresponding primitive.</p>
77 */
78 private static final Map PRIMITIVE_TYPES = new HashMap();
79 static {
80 PRIMITIVE_TYPES.put("boolean", boolean.class);
81 PRIMITIVE_TYPES.put("byte", byte.class);
82 PRIMITIVE_TYPES.put("char", char.class);
83 PRIMITIVE_TYPES.put("double", double.class);
84 PRIMITIVE_TYPES.put("float", float.class);
85 PRIMITIVE_TYPES.put("int", int.class);
86 PRIMITIVE_TYPES.put("long", long.class);
87 PRIMITIVE_TYPES.put("short", short.class);
88 }
89
90
91
92
93
94 /***
95 * <p>The <code>ValidatorAction</code> that we are wrapping.</p>
96 */
97 private ValidatorAction action = null;
98
99
100 /***
101 * <p>The class containing the validation method to be called for this action.</p>
102 */
103 private Class clazz = null;
104
105
106 /***
107 * <p>The field definition containing the mappings for parameter and
108 * message subtitution for this validator type.</p>
109 */
110 private Field field = null;
111
112
113 /***
114 * <p>The form definition corresponding to this validator type that is used
115 * for mapping parameter and message arguments.</p>
116 */
117 private Form form = null;
118
119
120 /***
121 * <p>Return an instance of the specified validation class, if the requested
122 * validation method is not static.</p>
123 */
124 private Object instance = null;
125
126
127 /***
128 * <p>Array of message arguments defining replacement parameters for error
129 * messages related to this validator.</p>
130 */
131 private Arg[] messageArgs = null;
132
133
134 /***
135 * <p>The validation <code>Method</code> to be called for this action.</p>
136 */
137 private Method method = null;
138
139
140 /***
141 * <p>Array of parameter arguments defining values to be sent in to
142 * the validator method for this validator.</p>
143 */
144 private Arg[] parameterArgs = null;
145
146
147 /***
148 * <p>The <code>ValidatorResources</code> for this application.</p>
149 */
150 private ValidatorResources resources = null;
151
152
153 /***
154 * <p>The parameter signature for the validation method to be called
155 * for this action.</p>
156 */
157 private Class[] signature = null;
158
159
160
161
162
163 /***
164 * <p>Return the <code>ValidatorAction</code> instance we are wrapping.</p>
165 */
166 public ValidatorAction getAction() {
167 return this.action;
168 }
169
170
171 /***
172 * <p>Return an instance of the requested validator class, if the requested
173 * validation method is not static. If the method is static, return
174 * <code>null</code> instead.</p>
175 */
176 public Object getInstance() {
177 return this.instance;
178 }
179
180
181 /***
182 * <p>Return an array of argument metadata describing subtitution values
183 * for error messages emitted by this validator type.</p>
184 */
185 public Arg[] getMessageArgs() {
186 return this.messageArgs;
187 }
188
189
190 /***
191 * <p>Return the lookup key for the error message template to be used
192 * if this validation fails.</p>
193 */
194 public String getMessageKey() {
195 return this.action.getMsg();
196 }
197
198
199 /***
200 * <p>Return the validation <code>Method</code> to be called for this
201 * action.</p>
202 */
203 public Method getMethod() {
204 return this.method;
205 }
206
207
208 /***
209 * <p>Return an array of argument metadata describing the parameter values
210 * to be sent to the validation method for this validator type.</p>
211 */
212 public Arg[] getParameterArgs() {
213 return this.parameterArgs;
214 }
215
216
217 /***
218 * <p>Return the parameter signature for the validation method to be called
219 * for this action.</p>
220 */
221 public Class[] getSignature() {
222 return this.signature;
223 }
224
225
226
227
228
229 /***
230 * <p>Precalculate the values to be returned by our public properties.</p>
231 *
232 * @exception IllegalArgumentException if configuration data is missing
233 * or incorrect
234 */
235 private void precalculate() {
236
237 List list = null;
238 String value = null;
239 String values = null;
240
241
242 ClassLoader loader = Thread.currentThread().getContextClassLoader();
243 if (loader == null) {
244 loader = this.getClass().getClassLoader();
245 }
246
247
248
249 try {
250 this.clazz = loader.loadClass(action.getClassname());
251 } catch (ClassNotFoundException e) {
252 throw new IllegalArgumentException("ClassNotFoundException:"
253 + " Cannot load class '" + action.getClassname()
254 + "' specified by ValidatorAction with name '"
255 + action.getName() + "'");
256 }
257
258
259
260 list = new ArrayList();
261 values = action.getMethodParams().trim();
262 while (values.length() > 0) {
263
264 int comma = values.indexOf(',');
265 if (comma >= 0) {
266 value = values.substring(0, comma).trim();
267 values = values.substring(comma + 1);
268 } else {
269 value = values.trim();
270 values = "";
271 }
272 if (value.length() == 0) {
273 break;
274 }
275
276 Class clazz = (Class) PRIMITIVE_TYPES.get(value);
277 if (clazz == null) {
278 try {
279 clazz = loader.loadClass(value);
280 } catch (ClassNotFoundException e) {
281 throw new IllegalArgumentException("ClassNotFoundException:"
282 + " Cannot load method parameter class '" + value
283 + "' specified by ValidatorAction with name '"
284 + action.getName() + "'");
285 }
286 }
287 list.add(clazz);
288 }
289 this.signature = (Class[]) list.toArray(new Class[list.size()]);
290
291
292 try {
293 this.method = this.clazz.getMethod(action.getMethod(), this.signature);
294 } catch (NoSuchMethodException e) {
295 throw new IllegalArgumentException("NoSuchMethodException:"
296 + " Method named '" + action.getMethod() + "' with parameters '"
297 + action.getMethodParams() + "' for class '" + action.getClassname()
298 + "' not found. Specified by ValidatorAction with name '"
299 + action.getName() + "'");
300 }
301
302
303
304 if (!Modifier.isStatic(this.method.getModifiers())) {
305 try {
306 this.instance = clazz.newInstance();
307 } catch (IllegalAccessException e) {
308 throw new IllegalArgumentException("IllegalAccessException:"
309 + " Not allowed to instantiate class '" + action.getClassname()
310 + "' specified by ValidatorAction with name '" + action.getName()
311 + "' (validation method with name '" + action.getMethod()
312 + "' is not static)");
313 } catch (InstantiationException e) {
314 throw new IllegalArgumentException("InstantiationException:"
315 + " Could not instantiate class '" + action.getClassname()
316 + "' specified by ValidatorAction with name '" + action.getName()
317 + "' (validation method with name '" + action.getMethod()
318 + "' is not static)");
319 }
320 }
321
322
323 this.form = resources.getForm(Locale.getDefault(),
324 FORM_NAME_PREFIX + action.getName());
325 if (this.form == null) {
326 throw new IllegalArgumentException(FORM_NAME_PREFIX + action.getName());
327 }
328
329
330
331 this.field = this.form.getField(action.getName());
332 if (this.field == null) {
333 throw new IllegalArgumentException("Field " + action.getName());
334 }
335 this.messageArgs = field.getArgs("message");
336 if (this.messageArgs == null) {
337 this.messageArgs = new Arg[0];
338 }
339 this.parameterArgs = field.getArgs("parameter");
340 if (this.parameterArgs == null) {
341 this.parameterArgs = new Arg[0];
342 }
343
344
345
346
347 if ((this.parameterArgs.length > 0)
348 && (this.parameterArgs[this.parameterArgs.length - 1] == null)) {
349 Arg[] results = new Arg[this.parameterArgs.length - 1];
350 System.arraycopy(this.parameterArgs, 0, results, 0, results.length);
351 this.parameterArgs = results;
352 }
353
354
355
356 if (this.parameterArgs.length != this.signature.length) {
357 throw new IllegalArgumentException(this.action.getName()
358 + ": signature defines " + this.signature.length
359 + " elements but " + this.parameterArgs.length
360 + " parameter arguments are specified");
361 }
362
363 }
364
365
366 }