001: package org.apache.ojb.broker.util;
002:
003: /* Copyright 2002-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.lang.reflect.InvocationTargetException;
019: import java.lang.reflect.Method;
020: import java.lang.reflect.Field;
021: import java.lang.reflect.Constructor;
022: import java.lang.reflect.Modifier;
023: import java.net.URL;
024:
025: import org.apache.ojb.broker.OJBRuntimeException;
026: import org.apache.ojb.broker.PersistenceBrokerException;
027: import org.apache.ojb.broker.metadata.ClassDescriptor;
028: import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
029:
030: /**
031: * Helper class with static methods for java class, method, and field handling.
032: *
033: * @version $Id: ClassHelper.java,v 1.10.2.3 2005/12/21 22:27:47 tomdz Exp $
034: */
035: public class ClassHelper {
036: /** Arguments for invoking a default or no-arg constructor */
037: private static final Object[] NO_ARGS = {};
038: /** Parameter types of a default/no-arg constructor */
039: private static final Class[] NO_ARGS_CLASS = {};
040:
041: /** The class loader currently used by OJB */
042: private static ClassLoader _classLoader = null;
043: /** A mutex for changing the class loader */
044: private static Object _mutex = new Object();
045:
046: /**
047: * Prevents instatiation.
048: */
049: private ClassHelper() {
050: }
051:
052: /**
053: * Sets the classloader to be used by OJB. This can be set by external
054: * application that need to pass a specific classloader to OJB.
055: *
056: * @param loader The class loader. If <code>null</code> then OJB will use
057: * the class loader of the current thread
058: */
059: public static void setClassLoader(ClassLoader loader) {
060: synchronized (_mutex) {
061: _classLoader = loader;
062: }
063: }
064:
065: /**
066: * Returns the class loader currently used by OJB. Defaults to the class loader of
067: * the current thread (<code>Thread.currentThread().getContextClassLoader()</code>)
068: * if not set differently. If class loader is not explicitly set and the loader for
069: * the current thread context is null, the JVM default class loader will be used.
070: *
071: * @return The classloader used by OJB
072: * @see #setClassLoader(ClassLoader)
073: */
074: public static ClassLoader getClassLoader() {
075: final ClassLoader ojbClassLoader;
076: if (_classLoader != null) {
077: ojbClassLoader = _classLoader;
078: } else {
079: final ClassLoader threadCtxtClassLoader;
080: threadCtxtClassLoader = Thread.currentThread()
081: .getContextClassLoader();
082: if (threadCtxtClassLoader == null) {
083: // mkalen: happens only in "obscure" situations using JNI, revert to system CL
084: ojbClassLoader = ClassLoader.getSystemClassLoader();
085: } else {
086: ojbClassLoader = threadCtxtClassLoader;
087: }
088: }
089: return ojbClassLoader;
090: }
091:
092: /**
093: * Determines the url of the indicated resource using the currently set class loader.
094: *
095: * @param name The resource name
096: * @return The resource's url
097: */
098: public static URL getResource(String name) {
099: return getClassLoader().getResource(name);
100: }
101:
102: /**
103: * Retrieves the class object for the given qualified class name.
104: *
105: * @param className The qualified name of the class
106: * @param initialize Whether the class shall be initialized
107: * @return The class object
108: */
109: public static Class getClass(String className, boolean initialize)
110: throws ClassNotFoundException {
111: return Class.forName(className, initialize, getClassLoader());
112: }
113:
114: /**
115: * Returns a new instance of the given class, using the default or a no-arg constructor.
116: *
117: * @param target The class to instantiate
118: * @return The instance
119: */
120: public static Object newInstance(Class target)
121: throws InstantiationException, IllegalAccessException {
122: return target.newInstance();
123: }
124:
125: /**
126: * Returns a new instance of the given class, using the default or a no-arg constructor.
127: * This method can also use private no-arg constructors if <code>makeAccessible</code>
128: * is set to <code>true</code> (and there are no other security constraints).
129: *
130: * @param target The class to instantiate
131: * @param makeAccessible If the constructor shall be made accessible prior to using it
132: * @return The instance
133: */
134: public static Object newInstance(Class target,
135: boolean makeAccessible) throws InstantiationException,
136: IllegalAccessException {
137: if (makeAccessible) {
138: try {
139: return newInstance(target, NO_ARGS_CLASS, NO_ARGS,
140: makeAccessible);
141: } catch (InvocationTargetException e) {
142: throw new OJBRuntimeException(
143: "Unexpected exception while instantiate class '"
144: + target + "' with default constructor",
145: e);
146: } catch (NoSuchMethodException e) {
147: throw new OJBRuntimeException(
148: "Unexpected exception while instantiate class '"
149: + target + "' with default constructor",
150: e);
151: }
152: } else {
153: return target.newInstance();
154: }
155: }
156:
157: /**
158: * Returns a new instance of the given class, using the constructor with the specified parameter types.
159: *
160: * @param target The class to instantiate
161: * @param types The parameter types
162: * @param args The arguments
163: * @return The instance
164: */
165: public static Object newInstance(Class target, Class[] types,
166: Object[] args) throws InstantiationException,
167: IllegalAccessException, IllegalArgumentException,
168: InvocationTargetException, NoSuchMethodException,
169: SecurityException {
170: return newInstance(target, types, args, false);
171: }
172:
173: /**
174: * Returns a new instance of the given class, using the constructor with the specified parameter types.
175: * This method can also use private constructors if <code>makeAccessible</code> is set to
176: * <code>true</code> (and there are no other security constraints).
177: *
178: * @param target The class to instantiate
179: * @param types The parameter types
180: * @param args The arguments
181: * @param makeAccessible If the constructor shall be made accessible prior to using it
182: * @return The instance
183: */
184: public static Object newInstance(Class target, Class[] types,
185: Object[] args, boolean makeAccessible)
186: throws InstantiationException, IllegalAccessException,
187: IllegalArgumentException, InvocationTargetException,
188: NoSuchMethodException, SecurityException {
189: Constructor con;
190:
191: if (makeAccessible) {
192: con = target.getDeclaredConstructor(types);
193: if (makeAccessible && !con.isAccessible()) {
194: con.setAccessible(true);
195: }
196: } else {
197: con = target.getConstructor(types);
198: }
199: return con.newInstance(args);
200: }
201:
202: /**
203: * Determines the method with the specified signature via reflection look-up.
204: *
205: * @param clazz The java class to search in
206: * @param methodName The method's name
207: * @param params The parameter types
208: * @return The method object or <code>null</code> if no matching method was found
209: */
210: public static Method getMethod(Class clazz, String methodName,
211: Class[] params) {
212: try {
213: return clazz.getMethod(methodName, params);
214: } catch (Exception ignored) {
215: }
216: return null;
217: }
218:
219: /**
220: * Determines the field via reflection look-up.
221: *
222: * @param clazz The java class to search in
223: * @param fieldName The field's name
224: * @return The field object or <code>null</code> if no matching field was found
225: */
226: public static Field getField(Class clazz, String fieldName) {
227: try {
228: return clazz.getField(fieldName);
229: } catch (Exception ignored) {
230: }
231: return null;
232: }
233:
234: // *******************************************************************
235: // Convenience methods
236: // *******************************************************************
237:
238: /**
239: * Convenience method for {@link #getClass(String, boolean) getClass(name, true)}
240: *
241: * @param name The qualified class name
242: * @return The class object
243: */
244: public static Class getClass(String name)
245: throws ClassNotFoundException {
246: return getClass(name, true);
247: }
248:
249: /**
250: * Returns a new instance of the class with the given qualified name using the default or
251: * or a no-arg constructor.
252: *
253: * @param className The qualified name of the class to instantiate
254: */
255: public static Object newInstance(String className)
256: throws InstantiationException, IllegalAccessException,
257: ClassNotFoundException {
258: return newInstance(getClass(className));
259: }
260:
261: /**
262: * Returns a new instance of the class with the given qualified name using the constructor with
263: * the specified signature.
264: *
265: * @param className The qualified name of the class to instantiate
266: * @param types The parameter types
267: * @param args The arguments
268: * @return The instance
269: */
270: public static Object newInstance(String className, Class[] types,
271: Object[] args) throws InstantiationException,
272: IllegalAccessException, IllegalArgumentException,
273: InvocationTargetException, NoSuchMethodException,
274: SecurityException, ClassNotFoundException {
275: return newInstance(getClass(className), types, args);
276: }
277:
278: /**
279: * Returns a new instance of the given class using the constructor with the specified parameter.
280: *
281: * @param target The class to instantiate
282: * @param type The types of the single parameter of the constructor
283: * @param arg The argument
284: * @return The instance
285: */
286: public static Object newInstance(Class target, Class type,
287: Object arg) throws InstantiationException,
288: IllegalAccessException, IllegalArgumentException,
289: InvocationTargetException, NoSuchMethodException,
290: SecurityException {
291: return newInstance(target, new Class[] { type },
292: new Object[] { arg });
293: }
294:
295: /**
296: * Returns a new instance of the class with the given qualified name using the constructor with
297: * the specified parameter.
298: *
299: * @param className The qualified name of the class to instantiate
300: * @param type The types of the single parameter of the constructor
301: * @param arg The argument
302: * @return The instance
303: */
304: public static Object newInstance(String className, Class type,
305: Object arg) throws InstantiationException,
306: IllegalAccessException, IllegalArgumentException,
307: InvocationTargetException, NoSuchMethodException,
308: SecurityException, ClassNotFoundException {
309: return newInstance(className, new Class[] { type },
310: new Object[] { arg });
311: }
312:
313: /**
314: * Determines the method with the specified signature via reflection look-up.
315: *
316: * @param object The instance whose class is searched for the method
317: * @param methodName The method's name
318: * @param params The parameter types
319: * @return A method object or <code>null</code> if no matching method was found
320: */
321: public static Method getMethod(Object object, String methodName,
322: Class[] params) {
323: return getMethod(object.getClass(), methodName, params);
324: }
325:
326: /**
327: * Determines the method with the specified signature via reflection look-up.
328: *
329: * @param className The qualified name of the searched class
330: * @param methodName The method's name
331: * @param params The parameter types
332: * @return A method object or <code>null</code> if no matching method was found
333: */
334: public static Method getMethod(String className, String methodName,
335: Class[] params) {
336: try {
337: return getMethod(getClass(className, false), methodName,
338: params);
339: } catch (Exception ignored) {
340: }
341: return null;
342: }
343:
344: /**
345: * Builds a new instance for the class represented by the given class descriptor.
346: *
347: * @param cld The class descriptor
348: * @return The instance
349: */
350: public static Object buildNewObjectInstance(ClassDescriptor cld) {
351: Object result = null;
352:
353: // If either the factory class and/or factory method is null,
354: // just follow the normal code path and create via constructor
355: if ((cld.getFactoryClass() == null)
356: || (cld.getFactoryMethod() == null)) {
357: try {
358: // 1. create an empty Object (persistent classes need a public default constructor)
359: Constructor con = cld.getZeroArgumentConstructor();
360: if (con == null) {
361: throw new ClassNotPersistenceCapableException(
362: "A zero argument constructor was not provided! Class was '"
363: + cld.getClassNameOfObject() + "'");
364: }
365: result = ConstructorHelper.instantiate(con);
366: } catch (InstantiationException e) {
367: throw new ClassNotPersistenceCapableException(
368: "Can't instantiate class '"
369: + cld.getClassNameOfObject() + "'");
370: }
371: } else {
372: try {
373: // 1. create an empty Object by calling the no-parms factory method
374: Method method = cld.getFactoryMethod();
375:
376: if (Modifier.isStatic(method.getModifiers())) {
377: // method is static so call it directly
378: result = method.invoke(null, null);
379: } else {
380: // method is not static, so create an object of the factory first
381: // note that this requires a public no-parameter (default) constructor
382: Object factoryInstance = cld.getFactoryClass()
383: .newInstance();
384:
385: result = method.invoke(factoryInstance, null);
386: }
387: } catch (Exception ex) {
388: throw new PersistenceBrokerException(
389: "Unable to build object instance of class '"
390: + cld.getClassNameOfObject()
391: + "' from factory:"
392: + cld.getFactoryClass() + "."
393: + cld.getFactoryMethod(), ex);
394: }
395: }
396: return result;
397: }
398: }
|