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 }