View Javadoc

1   /*
2    * Copyright 2000-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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                  /* VALIDATION */
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         // call the general validation for the entire business object
102         String msg = generalValidation(bean);
103         if (msg != null)
104         {
105             invalidFieldMessages.append(msg);
106             invalidFieldMessages.append(", ");            
107             valid = false;
108         }
109         
110         //System.out.println("invalidFieldMessages ["+invalidFieldMessages+"]");    
111         if (!valid)
112         {
113             //int lastComma = invalidFieldMessages.lastIndexOf(", ");
114             int lastComma = new String(invalidFieldMessages).lastIndexOf(", ");
115             String result = invalidFieldMessages.substring(0,lastComma);
116             // System.err.println("Had a validation problem and am throwing: "+invalidFieldMessages);    
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             //throw new Exception("property " + prop.getName() + " is of unsupported type " + propclass.toString());                                            
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() }; //{ java.lang.String.class };
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                 // System.err.println("EXCEPTION With the auto validation "+ e);
263                 return false;
264             }
265         }
266         catch (Exception e)
267         {
268             // System.err.println("EXCEPTION INVOKING METHOD " + methodName + " : " + e);
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;// WORK NEEDED
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;//work needed
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             // System.err.println("Auto validate: Date -- NOT IMPLEMENTED");
328             return true;//work needed
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             throw new Exception("property "
342                                 + prop.getName()
343                                 + " is of unsupported type "
344                                 + propclass.toString());
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