1 /***
2 * License Agreement.
3 *
4 * JSPA (POJO-SP)
5 *
6 * Copyright (C) 2009 HRX Pty Ltd
7 *
8 * This file is part of JSPA.
9 *
10 * JSPA is free software: you can redistribute it and/or modify it under the
11 * terms of the GNU Lesser General Public License version 3 as published by the
12 * Free Software Foundation.
13 *
14 * JSPA is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with JSPA. If not, see <http://www.gnu.org/licenses/>.
20 */
21 package com.hrx.rasp.util.dao.metadata;
22
23 import java.lang.annotation.Annotation;
24 import java.lang.reflect.Constructor;
25 import java.lang.reflect.Field;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 import java.lang.reflect.Modifier;
29 import java.sql.ResultSet;
30 import java.sql.SQLException;
31 import java.util.Arrays;
32
33 import org.apache.log4j.Logger;
34
35 import com.hrx.rasp.util.dao.NullValue;
36 import com.hrx.rasp.util.dao.StoredProcUtility;
37 import com.hrx.rasp.util.dao.annotations.DAOConstructor;
38 import com.hrx.rasp.util.dao.exception.GetterNotFoundException;
39 import com.hrx.rasp.util.dao.exception.InvalidFieldException;
40 import com.hrx.rasp.util.dao.exception.InvalidGetterException;
41 import com.hrx.rasp.util.dao.exception.InvalidSetterException;
42 import com.hrx.rasp.util.dao.exception.InvalidStoredProcedureException;
43 import com.hrx.rasp.util.dao.exception.SetterNotFoundException;
44 import com.hrx.rasp.util.dao.exception.StoredProcedurePrepareException;
45 import com.hrx.rasp.util.dao.exception.StoredProcedureProccessResultException;
46 import com.hrx.rasp.util.dao.operation.OperationType;
47
48 /***
49 * @author dan.stoica <dan.stoica@acslink.net.au>
50 *
51 */
52 public class MetadataHelper
53 {
54
55 private static Logger log = Logger.getLogger(MetadataHelper.class);
56
57 protected static final String GET_METHOD = "get";
58 protected static final String SET_METHOD = "set";
59
60 /***
61 * Invoke the method on a java Object.
62 */
63 public static Object invokeMethod(final Method method, final Object object, final Object[] values) throws IllegalAccessException,
64 InvocationTargetException
65 {
66
67 if (!method.isAccessible())
68 {
69 method.setAccessible(true);
70 }
71 return method.invoke(object, values);
72 }
73
74 /***
75 * Invoke the method on a java Object with null parameters.
76 */
77 public static Object invokeMethod(final Method method, final Object object) throws IllegalAccessException, InvocationTargetException
78 {
79 Object[] nullValues = {};
80 return invokeMethod(method, object, nullValues);
81 }
82
83 /***
84 * Does a recursive search for the method in the classes or it's superclass.
85 */
86 public static final Method getMethod(Class<?> pojoClass, String methodName, Class<?>[] methodParameterTypes) throws NoSuchMethodException
87 {
88
89
90
91
92 try
93 {
94 return getDeclaredMethod(pojoClass, methodName, methodParameterTypes);
95 }
96 catch (NoSuchMethodException e)
97 {
98 Class<?> superclass = pojoClass.getSuperclass();
99 if (superclass == null)
100 {
101 throw e;
102 }
103 else
104 {
105 return getMethod(superclass, methodName, methodParameterTypes);
106 }
107 }
108 }
109
110 /***
111 * Get a method declared in the given class and suppress the Java language
112 * access checking when it is used.
113 */
114 private static Method getDeclaredMethod(final Class<?> pojoClass, final String methodName, final Class<?>[] methodParameterTypes)
115 throws NoSuchMethodException
116 {
117 Method method = pojoClass.getDeclaredMethod(methodName, methodParameterTypes);
118 method.setAccessible(true);
119 return method;
120 }
121
122 /***
123 * Does a recursive search for the fields in the class or it's superclass.
124 */
125 public final static Field[] getDeclaredFields(Class<?> pojoClass)
126 {
127 Field[] fields = pojoClass.getDeclaredFields();
128
129
130
131 Class<?> superClass = pojoClass.getSuperclass();
132 if (superClass != null)
133 {
134 Field[] superFields = getDeclaredFields(superClass);
135
136 if (superFields.length > 0)
137 {
138 Field[] allFields = new Field[fields.length + superFields.length];
139 System.arraycopy(fields, 0, allFields, 0, fields.length);
140 System.arraycopy(superFields, 0, allFields, fields.length, superFields.length);
141 return allFields;
142 }
143 }
144 return fields;
145 }
146
147 /***
148 * Does a recursive search for the fields in the Object or it's super.
149 */
150 public final static <T> Field[] getDeclaredFields(T pojo)
151 {
152 Class<?> clazz = pojo.getClass();
153 Field[] fields = getDeclaredFields(clazz);
154 return fields;
155 }
156
157 protected static <T extends Annotation> StoredProcField<T> createStoredProcField(final Field field, final T parm)
158 throws StoredProcedurePrepareException, InvalidFieldException
159 {
160
161 StoredProcUtility.validateField(field);
162
163 String name = field.getName();
164 try
165 {
166 StoredProcField<T> spField = new StoredProcField<T>(name, field, parm);
167 if (log.isTraceEnabled())
168 {
169 log.trace("DAO: Found " + parm.annotationType().getSimpleName() + " parameter. Create field=" + name + ", param:" + spField);
170 }
171 return spField;
172 }
173 catch (Exception e)
174 {
175 throw new StoredProcedurePrepareException("Can not read the value for field:" + field.getName());
176 }
177 }
178
179 public static Object getPropertyValue(final Field field, final Object spBean) throws NoSuchMethodException, IllegalAccessException,
180 InvocationTargetException
181 {
182 String methodName = GET_METHOD + StoredProcUtility.capitalize(field.getName());
183
184 Class<?> myClass = spBean.getClass();
185 Method m = getGetMethod(myClass, methodName);
186
187 Object value = invokeMethod(m, spBean);
188
189 if (value == null)
190 {
191 value = NullValue.getFor(m.getReturnType());
192 }
193 return value;
194 }
195
196 public static Object setPropertyValue(Field field, Object value, Object spBean) throws StoredProcedureProccessResultException
197 {
198 String methodName = SET_METHOD + StoredProcUtility.capitalize(field.getName());
199
200 try
201 {
202 Class<?> myClass = spBean.getClass();
203
204 Class<?>[] params =
205 {
206 field.getType()
207 };
208 Method m = getMethod(myClass, methodName, params);
209 Object[] args =
210 {
211 value
212 };
213 invokeMethod(m, spBean, args);
214
215 }
216 catch (Exception e)
217 {
218 throw new StoredProcedureProccessResultException("Failed to call '" + methodName + "' method in dao (" + spBean + ")", e);
219 }
220
221 return value;
222 }
223
224 public static Method getGetMethod(Object spBean, String fieldName) throws NoSuchMethodException
225 {
226 String methodName = GET_METHOD + StoredProcUtility.capitalize(fieldName);
227 Class<?> myClass = spBean.getClass();
228 Method m = getGetMethod(myClass, methodName);
229 return m;
230 }
231
232 /***
233 * @param methodName
234 * @param myClass
235 * @return
236 * @throws NoSuchMethodException
237 */
238 private static Method getGetMethod(Class<?> myClass, String methodName) throws NoSuchMethodException
239 {
240 Class<?>[] params = {};
241 Method m = getMethod(myClass, methodName, params);
242 return m;
243 }
244
245 /***
246 * Find a target getter for a property field on a given class.
247 *
248 * @param spBean
249 * @param field
250 * @return the getter method
251 * @throws NoSuchMethodException
252 */
253 public static Method getGetMethod(Object spBean, Field field) throws NoSuchMethodException
254 {
255 Method m = getGetMethod(spBean, field.getName());
256 return m;
257 }
258
259 /***
260 * Find a target setter for a property field with a given parameter on a
261 * given class.
262 *
263 * @param spBean
264 * @param field
265 * @return the setter method
266 * @throws NoSuchMethodException
267 */
268 public static Method getSetMethod(Object spBean, Field field) throws NoSuchMethodException
269 {
270 String methodName = SET_METHOD + StoredProcUtility.capitalize(field.getName());
271 Class<?> myClass = spBean.getClass();
272 Class<?>[] params =
273 {
274 field.getType()
275 };
276 Method m = getMethod(myClass, methodName, params);
277 return m;
278 }
279
280 protected static void validateSettter(Object spBean, Field field) throws SetterNotFoundException, InvalidSetterException
281 {
282 try
283 {
284 Method m = MetadataHelper.getSetMethod(spBean, field);
285 int modifiers = m.getModifiers();
286 if (!Modifier.isPublic(modifiers))
287 {
288 throw new InvalidSetterException("Invalid Modifiers for method :" + m.getName() + ". The setters has to be public.");
289 }
290 }
291 catch (NoSuchMethodException e)
292 {
293
294
295
296 }
297 }
298
299 private static void validateGetter(Object spBean, Field field) throws GetterNotFoundException, InvalidGetterException
300 {
301 try
302 {
303 Method m = MetadataHelper.getGetMethod(spBean, field);
304 int modifiers = m.getModifiers();
305 if (!Modifier.isPublic(modifiers))
306 {
307 throw new InvalidGetterException("Invalid Modifiers for method :" + m.getName());
308 }
309 }
310 catch (NoSuchMethodException e)
311 {
312 throw new GetterNotFoundException("Getter not found for IN parameter:'" + field.getName(), e);
313 }
314 }
315
316 public static void validateGetterAndSetter(Object spBean, Field field) throws InvalidStoredProcedureException
317 {
318 MetadataHelper.validateGetter(spBean, field);
319 MetadataHelper.validateSettter(spBean, field);
320 }
321
322 /***
323 * @param rs
324 * @param cons
325 * @param parameterTypes
326 * @param args
327 * @return
328 * @throws SQLException
329 * @throws InstantiationException
330 * @throws IllegalAccessException
331 * @throws InvocationTargetException
332 */
333 public final static <T> T createInstance(ResultSet rs, Constructor<T> cons) throws SQLException, InstantiationException, IllegalAccessException,
334 InvocationTargetException
335 {
336 Class<?>[] parameterTypes = cons.getParameterTypes();
337 Object[] args = new Object[parameterTypes.length];
338 for (int index = 0; index < parameterTypes.length; index++)
339 {
340 Class<?> argc = parameterTypes[index];
341 args[index] = StoredProcUtility.getResultSetObject(rs, index + 1, argc);
342 }
343 T dao = cons.newInstance(args);
344 return dao;
345 }
346
347 /***
348 * Searches the Constructor operations array for the specified operation
349 * using the binary search algorithm. The array is sorted before the search.
350 *
351 * @param operation
352 * @param param
353 * @return true if the named Operation or 'ALL' operation is contained in
354 * the array
355 */
356 public static boolean isOperationDefined(final OperationType operation, DAOConstructor constr)
357 {
358 OperationType[] ops = constr.operation();
359 Arrays.sort(ops);
360 if (Arrays.binarySearch(ops, operation) >= 0)
361 {
362 return true;
363 }
364 return Arrays.binarySearch(ops, OperationType.ALL) >= 0;
365 }
366
367 }