1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.jetspeed.util.parser;
17
18 import java.beans.PropertyDescriptor;
19 import java.beans.IndexedPropertyDescriptor;
20 import java.beans.Introspector;
21 import java.lang.reflect.Method;
22
23 import java.math.BigDecimal;
24 import org.apache.torque.om.NumberKey;
25 import org.apache.torque.om.StringKey;
26 import java.util.Date;
27
28 import org.apache.turbine.util.ParameterParser;
29 import org.apache.turbine.util.pool.Recyclable;
30
31 import org.apache.jetspeed.util.ValidationException;
32 import org.apache.jetspeed.util.ValidationHelper;
33
34 /***
35 * A Turbine parameter parser with Validation built in.
36 * Validates any bean with methods that begin with validate[AttributeName].
37 * Works with Torque-generated beans.
38 * To use this class, override the TurbineResources.properties:
39 *
40 * services.RunDataService.default.parameter.parser=org.apache.turbine.util.parser.DefaultParameterParser
41 *
42 * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
43 * @version $Id: ValidationParameterParser.java,v 1.6 2004/02/23 03:18:08 jford Exp $
44 */
45 public class ValidationParameterParser
46 extends DefaultJetspeedParameterParser
47 implements ParameterParser,
48 Recyclable
49 {
50
51 public ValidationParameterParser()
52 {
53 super();
54 }
55
56 public ValidationParameterParser(String characterEncoding)
57 {
58 super (characterEncoding);
59 }
60
61
62 /***
63 * Uses bean introspection to set writable properties of bean from
64 * the parameters, where a (case-insensitive) name match between
65 * the bean property and the parameter is looked for.
66 *
67 * @param bean An Object.
68 * @exception Exception, a generic exception.
69 */
70 public void setProperties(Object bean)
71 throws Exception
72 {
73 Class beanClass = bean.getClass();
74 PropertyDescriptor[] props
75 = Introspector.getBeanInfo(beanClass).getPropertyDescriptors();
76 StringBuffer invalidFieldMessages = new StringBuffer("");
77 boolean valid = true;
78 for (int i = 0; i < props.length; i++)
79 {
80 String propname = props[i].getName();
81 Method setter = props[i].getWriteMethod();
82
83 if (setter != null &&
84 (containsKey(propname) ||
85 containsDateSelectorKeys(propname) ||
86 containsTimeSelectorKeys(propname)))
87 {
88
89 if (!validateProperty(bean, props[i]))
90 {
91 invalidFieldMessages.append("'");
92 invalidFieldMessages.append(propname);
93 invalidFieldMessages.append("' is not a valid field, ");
94 valid = false;
95 }
96 setMyProperty(bean, props[i]);
97
98 }
99 }
100
101
102 String msg = generalValidation(bean);
103 if (msg != null)
104 {
105 invalidFieldMessages.append(msg);
106 invalidFieldMessages.append(", ");
107 valid = false;
108 }
109
110
111 if (!valid)
112 {
113
114 int lastComma = new String(invalidFieldMessages).lastIndexOf(", ");
115 String result = invalidFieldMessages.substring(0,lastComma);
116
117 throw new ValidationException(result);
118 }
119 }
120
121 /***
122 * Set the property 'prop' in the bean to the value of the
123 * corresponding parameters. Supports all types supported by
124 * getXXX methods plus a few more that come for free because
125 * primitives have to be wrapped before being passed to invoke
126 * anyway.
127 *
128 * @param bean An Object.
129 * @param prop A PropertyDescriptor.
130 * @exception Exception, a generic exception.
131 */
132 protected void setMyProperty(Object bean,
133 PropertyDescriptor prop)
134 throws Exception
135 {
136 if (prop instanceof IndexedPropertyDescriptor)
137 {
138 throw new Exception(prop.getName() +
139 " is an indexed property (not supported)");
140 }
141
142 Method setter = prop.getWriteMethod();
143 if (setter == null)
144 {
145 throw new Exception(prop.getName() +
146 " is a read only property");
147 }
148
149 Object[] args = getArguments(prop);
150 try
151 {
152 setter.invoke(bean, args);
153 }
154 catch (Throwable t)
155 {
156 System.out.println("Validation: EXCEPTION (prop): " + prop.getName());
157 }
158 }
159
160
161 protected Object[] getArguments(PropertyDescriptor prop)
162 throws Exception
163 {
164 Class propclass = prop.getPropertyType();
165 Object[] args = { null };
166
167 if (propclass == String.class)
168 {
169 args[0] = getString(prop.getName());
170 }
171 else if (propclass == Integer.class || propclass == Integer.TYPE)
172 {
173 args[0] = getInteger(prop.getName());
174 }
175 else if (propclass == Short.class || propclass == Short.TYPE)
176 {
177 args[0] = new Short((short)(getInteger(prop.getName()).intValue()));
178 }
179 else if (propclass == Long.class || propclass == Long.TYPE)
180 {
181 args[0] = new Long(getLong(prop.getName()));
182 }
183 else if (propclass == Boolean.class || propclass == Boolean.TYPE)
184 {
185 args[0] = getBool(prop.getName());
186 }
187 else if (propclass == Double.class || propclass == Double.TYPE)
188 {
189 args[0] = new Double(getDouble(prop.getName()));
190 }
191 else if (propclass == BigDecimal.class)
192 {
193 args[0] = getBigDecimal(prop.getName());
194 }
195 else if (propclass == String[].class)
196 {
197 args[0] = getStrings(prop.getName());
198 }
199 else if (propclass == Object.class)
200 {
201 args[0] = getObject(prop.getName());
202 }
203 else if (propclass == int[].class)
204 {
205 args[0] = getInts(prop.getName());
206 }
207 else if (propclass == Integer[].class)
208 {
209 args[0] = getIntegers(prop.getName());
210 }
211 else if (propclass == Date.class)
212 {
213 args[0] = getDate(prop.getName());
214 }
215 else if (propclass == NumberKey.class)
216 {
217 args[0] = getNumberKey(prop.getName());
218 }
219 else if (propclass == StringKey.class)
220 {
221 args[0] = getStringKey(prop.getName());
222 }
223 else
224 {
225
226 }
227 return args;
228 }
229
230
231 /***
232 * Validate a bean's property based on definition in the business object
233 *
234 * @param bean The bean to be validated.
235 * @param prop The bean's property descriptor
236 * @return true if validation was successful, false if validation failed
237 **/
238 protected boolean validateProperty(Object bean,
239 PropertyDescriptor prop)
240 throws Exception
241 {
242 String propertyName = prop.getName();
243 String methodName = "validate" +
244 Character.toUpperCase(propertyName.charAt(0)) +
245 propertyName.substring(1);
246
247 Class[] signatureParams = { prop.getPropertyType() };
248 Object[] methodParams = getArguments(prop);
249 try
250 {
251 Method method = bean.getClass().getMethod(methodName, signatureParams);
252 boolean isValidBool = ((Boolean)method.invoke(bean, methodParams)).booleanValue();
253 return isValidBool;
254 }
255 catch (NoSuchMethodException nsm_e)
256 {
257 try{
258 return validateObject(prop);
259 }
260 catch (Exception e)
261 {
262
263 return false;
264 }
265 }
266 catch (Exception e)
267 {
268
269 }
270 return true;
271 }
272
273
274 protected boolean validateObject(PropertyDescriptor prop)
275 throws Exception
276 {
277 Class propclass = prop.getPropertyType();
278 Object[] args = { null };
279
280 if (propclass == String.class)
281 {
282 return ValidationHelper.isAlphaNumeric(getString(prop.getName()), false);
283 }
284 else if (propclass == Integer.class || propclass == Integer.TYPE)
285 {
286 return ValidationHelper.isInteger(getString(prop.getName()), false);
287 }
288 else if (propclass == Short.class || propclass == Short.TYPE)
289 {
290 return ValidationHelper.isInteger(getString(prop.getName()), false);
291 }
292 else if (propclass == Long.class || propclass == Long.TYPE)
293 {
294 return ValidationHelper.isDecimal(getString(prop.getName()), false);
295 }
296 else if (propclass == Boolean.class || propclass == Boolean.TYPE)
297 {
298 return true;
299 }
300 else if (propclass == Double.class || propclass == Double.TYPE)
301 {
302 return ValidationHelper.isDecimal(getString(prop.getName()), false);
303 }
304 else if (propclass == BigDecimal.class)
305 {
306 return ValidationHelper.isDecimal(getString(prop.getName()), false);
307 }
308 else if (propclass == String[].class)
309 {
310 return ValidationHelper.isAlphaNumeric(getString(prop.getName()), false);
311 }
312 else if (propclass == Object.class)
313 {
314 System.err.println("Auto validate: Object-- NOT IMPLEMENTED");
315 return true;
316 }
317 else if (propclass == int[].class)
318 {
319 return ValidationHelper.isInteger(getString(prop.getName()), false);
320 }
321 else if (propclass == Integer[].class)
322 {
323 return ValidationHelper.isInteger(getString(prop.getName()), false);
324 }
325 else if (propclass == Date.class)
326 {
327
328 return true;
329 }
330 else if (propclass == NumberKey.class)
331 {
332 return ValidationHelper.isInteger(getString(prop.getName()), false);
333 }
334 else if (propclass == StringKey.class)
335 {
336 return ValidationHelper.isInteger(getString(prop.getName()), false);
337 }
338 else
339 {
340
341
342
343
344
345
346 }
347 return false;
348 }
349
350 /***
351 * Validate a bean's property based on definition in the business object
352 *
353 * @param bean The bean to be validated.
354 * @param prop The bean's property descriptor
355 * @return null if validation was successful, an error message if validation failed
356 **/
357 protected String generalValidation(Object bean)
358 throws Exception
359 {
360 String methodName = "validate";
361 try
362 {
363 Method method = bean.getClass().getMethod(methodName, null);
364 String msg = (String)method.invoke(bean, null);
365 return msg;
366 }
367 catch (NoSuchMethodException nsm_e)
368 {
369 }
370 catch (Exception e)
371 {
372 System.err.println("EXCEPTION INVOKING METHOD " + methodName + " : " + e);
373 }
374 return null;
375 }
376
377
378 }
379
380