001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015: package org.griphyn.common.util;
016:
017: import java.lang.reflect.*;
018:
019: /**
020: * This class provides a dynamic class loading facility. It is
021: * tightly coupled to the property facility. To dynamically obtain
022: * an instance of a class through its constructor:
023: *
024: * <pre>
025: * Integer i = null;
026: * DynamicLoader dl = new DynamicLoader( "java.lang.Integer" );
027: * try {
028: * // instantiate as Integer("42")
029: * String arg[] = new String[1];
030: * arg[0] = "42";
031: * i = (Integer) dl.instantiate(arg);
032: * } catch ( Exception e ) {
033: * System.err.println( dl.convertException(e) );
034: * System.exit(1);
035: * }
036: * </pre>
037: *
038: * Similarily, to obtain an instance of a class through a static
039: * method provided by the same class, or another class:
040: *
041: * <pre>
042: * Integer i = null;
043: * DynamicLoader dl = new DynamicLoader( "java.lang.Integer" );
044: * try {
045: * // instantiate as Integer("42")
046: * String arg[] = new String[1];
047: * arg[0] = "42";
048: * i = (Integer) dl.static_method( "valueOf", arg );
049: * } catch ( Exception e ) {
050: * System.err.println( dl.convertException(e) );
051: * System.exit(1);
052: * }
053: * </pre>
054:
055: *
056: * @author Karan Vahi
057: * @author Jens-S. Vöckler
058: * @version $Revision: 50 $
059: */
060: public class DynamicLoader {
061: /**
062: * Stores the fully qualified class name to dynamically instantiate.
063: */
064: private String m_classname;
065:
066: /**
067: *
068: */
069: public DynamicLoader(String classname) {
070: if ((this .m_classname = classname) == null)
071: throw new NullPointerException(
072: "You must specify a fully-qualified class name");
073: }
074:
075: /**
076: * Sets the fully-qualified class name to load.
077: * @param classname is the new class name.
078: * @see #getClassName()
079: */
080: public void setClassName(String classname) {
081: if ((this .m_classname = classname) == null)
082: throw new NullPointerException(
083: "You must specify a fully-qualified class name");
084: }
085:
086: /**
087: * Obtains the fully-qualified class name that this instance works with.
088: * @return the class name.
089: * @see #setClassName( String )
090: */
091: public String getClassName() {
092: return this .m_classname;
093: }
094:
095: /**
096: * Dynamically instantiates a class from a contructor. You must have
097: * set the class name before invoking this method. Please note that
098: * any exceptions thrown by the constructor will be wrapped into a
099: * <code>InvocationTargetException</code>.
100: *
101: * @param arguments are arguments to the constructor of the class
102: * to load. Please use "new Object[0]" for the argumentless default
103: * constructor.
104: * @return an instance that must be cast to the correct class.
105: *
106: * @exception ClassNotFoundException if the driver for the database
107: * cannot be loaded. You might want to check your CLASSPATH, too.
108: * @exception NoSuchMethodException if the driver's constructor interface
109: * does not comply with the database driver API.
110: * @exception InstantiationException if the driver class is an abstract
111: * class instead of a concrete implementation.
112: * @exception IllegalAccessException if the constructor for the driver
113: * class it not publicly accessible to this package.
114: * @exception InvocationTargetException if the constructor of the driver
115: * throws an exception while being dynamically loaded.
116: * @exception SQLException if the driver for the database can be
117: * loaded, but faults when initially accessing the database
118: *
119: * @see #setClassName( String )
120: */
121: public Object instantiate(Object[] arguments)
122: throws ClassNotFoundException, NoSuchMethodException,
123: InstantiationException, IllegalAccessException,
124: InvocationTargetException {
125: // generate class array and populate with class of each argument
126: Class[] temp = new Class[arguments.length];
127: for (int i = 0; i < arguments.length; ++i)
128: temp[i] = arguments[i].getClass();
129:
130: // load class into memory and obtain an instance of it
131: return Class.forName(m_classname).getConstructor(temp)
132: .newInstance(arguments);
133: }
134:
135: /**
136: * Dynamically instantiates a class from a contructor. You must have
137: * set the class name before invoking this method. Please note that
138: * any exceptions thrown by the constructor will be wrapped into a
139: * <code>InvocationTargetException</code>.<p>
140: * This method should be invoked, if the constructor declares
141: * interface types as formal arguments, but the actual arguments
142: * are implementation classes.
143: *
144: * @param classes is a vector of the classes involved. Each item
145: * in the classes vector matches the item in the arguments vector.
146: * The classes vector will be used to select the correct constructor.
147: * Please use "new Class[0]" for the argumentless default ctor.
148: * @param arguments are arguments to the constructor of the class
149: * to load. Please use "new Object[0]" for the argumentless default
150: * constructor.
151: * @return an instance that must be cast to the correct class.
152: *
153: * @exception ClassNotFoundException if the driver for the database
154: * cannot be loaded. You might want to check your CLASSPATH, too.
155: * @exception NoSuchMethodException if the driver's constructor interface
156: * does not comply with the database driver API.
157: * @exception IllegalArgumentException is thrown, if the number of
158: * arguments do not match the number of types, ie the vector have
159: * mismatching sizes.
160: * @exception InstantiationException if the driver class is an abstract
161: * class instead of a concrete implementation.
162: * @exception IllegalAccessException if the constructor for the driver
163: * class it not publicly accessible to this package.
164: * @exception InvocationTargetException if the constructor of the driver
165: * throws an exception while being dynamically loaded.
166: * @exception SQLException if the driver for the database can be
167: * loaded, but faults when initially accessing the database
168: *
169: * @see #setClassName( String )
170: */
171: public Object instantiate(Class[] classes, Object[] arguments)
172: throws ClassNotFoundException, NoSuchMethodException,
173: InstantiationException, IllegalAccessException,
174: InvocationTargetException {
175: // complain on argument mismatch
176: if (classes.length != arguments.length)
177: throw new IllegalArgumentException(
178: "vector sizes must match");
179:
180: // load class into memory and obtain an instance of it
181: return Class.forName(m_classname).getConstructor(classes)
182: .newInstance(arguments);
183: }
184:
185: /**
186: * Dynamically instantiates a class from a static method which
187: * constructs the resulting object. You must have set the class name
188: * before invoking this method. Please note that any exceptions thrown
189: * by the constructor will be wrapped into a
190: * <code>InvocationTargetException</code>.
191: *
192: * @param method is the name of the static method to call.
193: * @param arguments are arguments to the constructor of the class
194: * to load. Please use "new Object[0]" for the argumentless default
195: * constructor.
196: * @return an instance that must be cast to the correct class.
197: *
198: * @exception ClassNotFoundException if the driver for the database
199: * cannot be loaded. You might want to check your CLASSPATH, too.
200: * @exception NoSuchMethodException if the driver's constructor interface
201: * does not comply with the database driver API.
202: * @exception InstantiationException if the driver class is an abstract
203: * class instead of a concrete implementation.
204: * @exception IllegalAccessException if the constructor for the driver
205: * class it not publicly accessible to this package.
206: * @exception InvocationTargetException if the constructor of the driver
207: * throws an exception while being dynamically loaded.
208: * @exception SQLException if the driver for the database can be
209: * loaded, but faults when initially accessing the database
210: * @exception SecurityException if you are not permitted to invoke the
211: * method, or even list the methods provided by the class.
212: * @exception NullPointerException if the method name is
213: * <code>null</code>.
214: * @exception IllegalArgumentException if the number of actual and
215: * formal parameter differ, unwrapping a primitive type failed, or
216: * a parameter value cannot be converted to the formal argument type.
217: *
218: * @see #setClassName( String )
219: */
220: public Object static_method(String method, Object[] arguments)
221: throws ClassNotFoundException, SecurityException,
222: NoSuchMethodException, InstantiationException,
223: IllegalAccessException, InvocationTargetException,
224: NullPointerException, IllegalArgumentException {
225: // generate class array and populate with class of each argument
226: Class[] temp = new Class[arguments.length];
227: for (int i = 0; i < arguments.length; ++i)
228: temp[i] = arguments[i].getClass();
229:
230: // load the class into memory, and find the method, and invoke it as
231: // a static method
232: return Class.forName(m_classname).getDeclaredMethod(method,
233: temp).invoke(null, arguments);
234: }
235:
236: /**
237: * Converts an exception from the class loader into an error message.
238: *
239: * @param classname is the name or some other class signifier.
240: * @param e is the exception thrown by the class loader.
241: * @return a string that tries to describe what went wrong.
242: */
243: static public String convertException(String classname, Exception e) {
244: String result = null;
245:
246: // check exceptions
247: result = convertExceptionToString(classname, e);
248:
249: //Commented out, as defined in convertToString(String,Exception) function
250: //Karan April 25, 2006
251: // if ( e instanceof ClassNotFoundException ) {
252: // result = "Unable to dynamically load " + classname;
253: // // do cause
254: // } else if ( e instanceof NoSuchMethodException ) {
255: // result = "Unable to dynamically invoke the constructor of " + classname;
256: // // no cause
257: // } else if ( e instanceof InstantiationException ) {
258: // result = "The dynamically loadable class " + classname + " is either " +
259: // "abstract or an interface";
260: // // no cause
261: // } else if ( e instanceof IllegalAccessException ) {
262: // result = "Unable to access appropriate constructor in " + classname;
263: // // no cause
264: // } else if ( e instanceof InvocationTargetException ) {
265: // result = "Class " + classname + " threw exception " +
266: // e.getClass().getName() + " during construction";
267: // // do cause
268: // } else if ( e instanceof IllegalArgumentException ) {
269: // result = "Class " + classname + " threw exception " +
270: // e.getClass().getName() + " during method invocation argument " +
271: // "list construction";
272: // } else if ( e instanceof NullPointerException ) {
273: // result = "Invalid static initializer method name for " + classname;
274: // // no cause
275: // } else if ( e instanceof SecurityException ) {
276: // result = "Prohibited access to " + classname;
277: // // ?? cause
278: // } else {
279: // result = classname + " caugth " + e.getClass().getName();
280: // // ?? cause
281: // }
282:
283: // append complete cause chain
284: int i = 0;
285: for (Throwable cause = e.getCause(); cause != null; cause = cause
286: .getCause()) {
287: result += " [" + Integer.toString(++i) + "]: " + cause;
288: }
289:
290: // done
291: return result;
292: }
293:
294: /**
295: * Converts an exception from the class loader into an error message.
296: *
297: * @param e is the exception thrown by the class loader.
298: * @return a string that tries to describe what went wrong.
299: */
300: public String convertException(Exception e) {
301: return DynamicLoader.convertException(m_classname, e);
302: }
303:
304: /**
305: * Converts an exception from the class loader into an error message.
306: * Note: It does not convert any cause messages.
307: *
308: * @param classname is the name or some other class signifier.
309: * @param e is the exception thrown by the class loader.
310: * @return a string that tries to describe what went wrong.
311: */
312: static public String convertExceptionToString(String classname,
313: Throwable e) {
314: String result = null;
315:
316: // check exceptions
317: if (e instanceof ClassNotFoundException) {
318: result = "Unable to dynamically load " + classname;
319: // do cause
320: } else if (e instanceof NoSuchMethodException) {
321: result = "Unable to dynamically invoke the constructor of "
322: + classname;
323: // no cause
324: } else if (e instanceof InstantiationException) {
325: result = "The dynamically loadable class " + classname
326: + " is either " + "abstract or an interface";
327: // no cause
328: } else if (e instanceof IllegalAccessException) {
329: result = "Unable to access appropriate constructor in "
330: + classname;
331: // no cause
332: } else if (e instanceof InvocationTargetException) {
333: result = "Class " + classname + " threw exception "
334: + e.getClass().getName() + " during construction";
335: // do cause
336: } else if (e instanceof IllegalArgumentException) {
337: result = "Class " + classname + " threw exception "
338: + e.getClass().getName()
339: + " during method invocation argument "
340: + "list construction";
341: } else if (e instanceof NullPointerException) {
342: result = "Invalid static initializer method name for "
343: + classname;
344: // no cause
345: } else if (e instanceof SecurityException) {
346: result = "Prohibited access to " + classname;
347: // ?? cause
348: } else {
349: result = classname + " caught " + e.getClass().getName()
350: + " " + e.getMessage();
351: // ?? cause
352: }
353:
354: // done
355: return result;
356: }
357:
358: }
|