001: /*
002: * @(#)ClassLoadHelper.java
003: *
004: * Copyright (C) 2000,,2003 2002 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a
009: * copy of this software and associated documentation files (the "Software"),
010: * to deal in the Software without restriction, including without limitation
011: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
012: * and/or sell copies of the Software, and to permit persons to whom the
013: * Software is furnished to do so, subject to the following conditions:
014: *
015: * The above copyright notice and this permission notice shall be included in
016: * all copies or substantial portions of the Software.
017: *
018: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
019: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
020: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
021: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
022: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
023: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
024: * DEALINGS IN THE SOFTWARE.
025: */
026:
027: package net.sourceforge.groboutils.util.classes.v1;
028:
029: import java.util.Vector;
030: import java.util.Hashtable;
031: import java.util.Enumeration;
032:
033: import java.io.InputStream;
034: import java.io.IOException;
035:
036: import java.net.URL;
037:
038: import java.lang.reflect.Method;
039:
040: import org.apache.log4j.Logger;
041:
042: /**
043: * Utility class for loading classes and creating instances. Much of the
044: * basic operation have been ripped from
045: * <tt>net.groboutils.util.classes.v1.ClassUtil</tt> in the GroboUtils package.
046: * If the helper's class loader is <tt>null</tt>, then it will use the Thread's
047: * context ClassLoader.
048: * <P>
049: * Note that resource loading is very tricky. Finding the right classloader
050: * and right methods to invoke is JDK dependent.
051: *
052: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
053: * @version $Date: 2003/02/10 22:52:36 $
054: * @since March 16, 2002
055: */
056: public class ClassLoadHelper {
057: private static final Logger LOG = Logger.getLogger(SPILoader.class
058: .getName());
059:
060: private static Method M_GET_CONTEXT_CLASSLOADER = discoverContextClassloaderMethod();
061: private static Method M_GET_RESOURCES = discoverGetResourcesMethod();
062: private static Method M_GET_SYSTEM_RESOURCES = discoverGetSystemResourcesMethod();
063:
064: private ClassLoader classLoader = null;
065:
066: /**
067: * Default constructor - will use the Thread's context class loader for
068: * each class discovery.
069: */
070: public ClassLoadHelper() {
071: this ((ClassLoader) null);
072: }
073:
074: /**
075: * Use the given class's classloader.
076: *
077: * @param clazz the class to pull the classloader from.
078: * @exception NullPointerException if <tt>clazz</tt> is <tt>null</tt>.
079: */
080: public ClassLoadHelper(Class clazz) {
081: this (clazz.getClassLoader());
082: }
083:
084: /**
085: * Loads the helper with the given class loader. If the given class loader
086: * is <tt>null</tt>, then it will use the Thread's context class loader.
087: *
088: * @param cl the classloader to pull all requested classes from, or
089: * it will use the thread's context class loader if <tt>cl</tt> is
090: * <tt>null</tt>.
091: * @see java.lang.Thread#getContextClassLoader()
092: */
093: public ClassLoadHelper(ClassLoader cl) {
094: this .classLoader = cl;
095: }
096:
097: //----------------------------
098: // Public methods
099:
100: /**
101: * Loads the requested class from the helper's classloader, and returns
102: * the Class instance, or <tt>null</tt> if the class could not be
103: * found.
104: *
105: * @param name the name of the class to load.
106: * @return the discovered Class, or <tt>null</tt> if it could not be found.
107: */
108: public Class getClass(String name) {
109: return getClass(name, true);
110: }
111:
112: /**
113: * Loads the requested class from the helper's classloader, and returns
114: * the Class instance, or <tt>null</tt> if the class could not be
115: * found.
116: *
117: * @param name the name of the class to load.
118: * @param swallowExceptions <tt>true</tt> if this method is to return
119: * @return the discovered Class, or <tt>null</tt> if it could not be found
120: * and <tt>swallowExceptions</tt> is true.
121: * @exception IllegalStateException if there was an error during
122: * initialization and <tt>swallowExceptions</tt> is <tt>false</tt>.
123: */
124: public Class getClass(String name, boolean swallowExceptions) {
125: Class c = null;
126:
127: if (name != null) {
128: Throwable error = null;
129: try {
130: c = loadClass(name);
131: } catch (ClassNotFoundException cnfe) {
132: error = cnfe;
133: } catch (LinkageError le) {
134: error = le;
135: } catch (IllegalArgumentException iae) {
136: error = iae;
137: }
138: if (error != null) {
139: LOG.info("getClass( " + name + " ) threw exception",
140: error);
141:
142: if (!swallowExceptions) {
143: throw new IllegalStateException(error.toString());
144: }
145: }
146: } else {
147: c = null;
148: }
149: return c;
150: }
151:
152: /**
153: * Creates a new instance of the class with the given <tt>className</tt>
154: * using the default constructor. If there was an error during the
155: * creation, such as the class was not found, the class does not have
156: * a default constructor, or the constructor threw an exception, then
157: * <tt>null</tt> is returned.
158: *
159: * @param className the name of the class to create an instance.
160: * @return the new instance, or <tt>null</tt> if there was a problem.
161: * @see #getClass( String )
162: * @see #createObject( String, boolean )
163: * @see #createObject( Class )
164: * @see #createObject( Class, boolean )
165: */
166: public Object createObject(String className) {
167: return createObject(getClass(className), true);
168: }
169:
170: /**
171: * Creates a new instance of the class with the given <tt>className</tt>
172: * using the default constructor. If there was an error during the
173: * creation, such as the class was not found, the class does not have
174: * a default constructor, or the constructor threw an exception, then an
175: * IllegalStateException will be thrown only if <tt>swallowExceptions</tt>
176: * is <tt>false</tt>; otherwise, <tt>null</tt> will be returned.
177: *
178: * @param className the name of the class to create an instance.
179: * @param swallowExceptions <tt>true</tt> if this method is to return
180: * <tt>null</tt> on any exceptions, or <tt>false</tt> if it should
181: * throw an IllegalStateException on any error.
182: * @return the new instance.
183: * @exception IllegalStateException if there was an error during
184: * initialization and <tt>swallowExceptions</tt> is <tt>false</tt>.
185: * @see #getClass( String )
186: * @see #createObject( String )
187: * @see #createObject( Class )
188: * @see #createObject( Class, boolean )
189: */
190: public Object createObject(String className,
191: boolean swallowExceptions) {
192: return createObject(getClass(className, swallowExceptions),
193: swallowExceptions);
194: }
195:
196: /**
197: * Creates an Object from the given Class, using its default constructor.
198: * All creation exceptions are swallowed. If the object could not
199: * be created, then <tt>null</tt> is returned.
200: *
201: * @param c the Class object from which a new instance will be created
202: * using its default constructor.
203: * @return the instantiated object, or <tt>null</tt> if <tt>c</tt> is
204: * <tt>null</tt>, or if there was an error during initialization.
205: */
206: public Object createObject(Class c) {
207: return createObject(c, true);
208: }
209:
210: /**
211: * Creates an Object from the given Class, using its default constructor.
212: * If there was an error during the
213: * creation, such as the class was not found, the class does not have
214: * a default constructor, or the constructor threw an exception, then an
215: * IllegalStateException will be thrown only if <tt>swallowExceptions</tt>
216: * is <tt>false</tt>; otherwise, <tt>null</tt> will be returned.
217: *
218: * @param c the Class object from which a new instance will be created
219: * using its default constructor.
220: * @param swallowExceptions <tt>true</tt> if this method is to return
221: * <tt>null</tt> on any exceptions, or <tt>false</tt> if it should
222: * throw an IllegalStateException on any error.
223: * @return the instantiated object, or <tt>null</tt> if <tt>c</tt> is
224: * <tt>null</tt>, or if there was an error during initialization and
225: * <tt>swallowExceptions</tt> is <tt>true</tt>.
226: * @exception IllegalStateException if there was an error during
227: * initialization and <tt>swallowExceptions</tt> is <tt>false</tt>.
228: */
229: public Object createObject(Class c, boolean swallowExceptions) {
230: if (c == null) {
231: return null;
232: }
233:
234: Throwable error = null;
235: Object obj = null;
236: try {
237: obj = c.newInstance();
238: } catch (InstantiationException ie) {
239: error = ie;
240: } catch (IllegalAccessException iae) {
241: error = iae;
242: } catch (NoSuchMethodError nsme) {
243: error = nsme;
244: }
245: if (error != null) {
246: LOG
247: .info("createObject( " + c + " ) threw exception",
248: error);
249:
250: if (!swallowExceptions) {
251: // Note about error.getMessage(): JDK 1.1 may have a 'null'
252: // error message thrown above. Some test cases have
253: // encountered this.
254:
255: throw new IllegalStateException(
256: "Could not instantiate " + c.getName() + ": "
257: + error.toString());
258: }
259: }
260: // else
261: return obj;
262: }
263:
264: /**
265: * Loads an object using the {@link #createObject( String, boolean )}
266: * method above, using the given System property's value as the
267: * class name. If the System property is not defined, then it resorts to
268: * the default class.
269: *
270: * @param propertyClassName the System Property name, whose value will be
271: * used as a fully-qualified Class name to load and instantiate and
272: * return.
273: * @param defaultClass if the System Property <tt>propertyClassName</tt>
274: * is not defined, then this will be the class to instantiate and
275: * return.
276: * @param swallowExceptions <tt>true</tt> if this method is to return
277: * <tt>null</tt> on any exceptions, or <tt>false</tt> if it should
278: * throw an IllegalStateException on any error.
279: * @return the instantiated class.
280: * @exception IllegalStateException if there was an error during
281: * initialization and <tt>swallowExceptions</tt> is <tt>false</tt>.
282: */
283: public Object createObjectFromProperty(String propertyClassName,
284: Class defaultClass, boolean swallowExceptions) {
285: return createObjectFromProperty(propertyClassName,
286: defaultClass, null, swallowExceptions);
287: }
288:
289: /**
290: * Loads an object using the {@link #createObject( String, boolean )}
291: * method above, using the given Hashtable's property's value as the
292: * class name. If the Hashtable property is not defined, then it resorts to
293: * the default class. If the Hashtable is <tt>null</tt>, then the
294: * System property will be used instead.
295: *
296: * @param propertyClassName the System Property name, whose value will be
297: * used as a fully-qualified Class name to load and instantiate and
298: * return.
299: * @param defaultClass if the System Property <tt>propertyClassName</tt>
300: * is not defined, then this will be the class to instantiate and
301: * return.
302: * @param properties a Hashtable of String -> String mappings.
303: * @param swallowExceptions <tt>true</tt> if this method is to return
304: * <tt>null</tt> on any exceptions, or <tt>false</tt> if it should
305: * throw an IllegalStateException on any error.
306: * @return the instantiated class.
307: * @exception IllegalStateException if there was an error during
308: * initialization and <tt>swallowExceptions</tt> is <tt>false</tt>.
309: */
310: public Object createObjectFromProperty(String propertyClassName,
311: Class defaultClass, Hashtable properties,
312: boolean swallowExceptions) {
313: Object o = null;
314: String cname = null;
315: if (properties == null) {
316: cname = System.getProperty(propertyClassName);
317: } else {
318: cname = (String) properties.get(propertyClassName);
319: }
320: if (cname == null) {
321: o = createObject(defaultClass, swallowExceptions);
322: } else {
323: o = createObject(cname, swallowExceptions);
324: }
325: return o;
326: }
327:
328: /**
329: * Loads a resource with the given name, using the correct ClassLoader.
330: * Does not swallow exceptions. See the JDK documentation on resources
331: * (they are pretty much files that are in the classpath of the
332: * classloader). Yes, this can be used successfully to get a class file
333: * (well, JDK 1.1 throws a SecurityException if this is attempted).
334: *
335: * @param name absolute referece to the expected resource.
336: * @return the resource as an InputStream, which may possibly be
337: * <tt>null</tt>.
338: * @exception IOException if an I/O error occurs.
339: * @see java.lang.ClassLoader#getResource( String )
340: * @see java.lang.ClassLoader#getResourceAsStream( String )
341: */
342: public InputStream getResourceAsStream(String name)
343: throws IOException {
344: ClassLoader cl = getClassLoader();
345: InputStream is = null;
346: if (cl == null) {
347: name = getAbsoluteResourceName(name);
348: is = this .getClass().getResourceAsStream(name);
349: } else {
350: is = cl.getResourceAsStream(name);
351: }
352: return is;
353: }
354:
355: /**
356: * Loads a resource with the given name, using the correct ClassLoader.
357: * Does not swallow exceptions. See the JDK documentation on resources
358: * (they are pretty much files that are in the classpath of the
359: * classloader). Yes, this can be used successfully to get a class file
360: * (well, JDK 1.1 throws a SecurityException if this is attempted).
361: *
362: * @param name absolute referece to the expected resource.
363: * @return the resource name as an URL, which may possibly be
364: * <tt>null</tt>.
365: * @exception IOException if an I/O error occurs.
366: * @see java.lang.ClassLoader#getResource( String )
367: * @see java.lang.ClassLoader#getResourceAsStream( String )
368: */
369: public URL getResource(String name) throws IOException {
370: return getResource(name, getClassLoader());
371: }
372:
373: /**
374: * Loads a resource with the given name, using the given ClassLoader.
375: * Does not swallow exceptions. See the JDK documentation on resources
376: * (they are pretty much files that are in the classpath of the
377: * classloader). Yes, this can be used successfully to get a class file
378: * (well, JDK 1.1 throws a SecurityException if this is attempted).
379: *
380: * @param name absolute referece to the expected resource.
381: * @param cl the classloader to load the reference from.
382: * @return the resource name as an URL, which may possibly be
383: * <tt>null</tt>.
384: * @exception IOException if an I/O error occurs.
385: * @see java.lang.ClassLoader#getResource( String )
386: * @see java.lang.ClassLoader#getResourceAsStream( String )
387: */
388: public URL getResource(String name, ClassLoader cl)
389: throws IOException {
390: LOG.debug("Enter getResource( " + name + " )");
391: URL url = null;
392: if (cl != null) {
393: // JDK 1.2+ can be awfully fickle. Allow for an alternative
394: // if this fails, through the use of the next IF statement.
395: url = cl.getResource(name);
396: }
397:
398: if (url == null) {
399: name = getAbsoluteResourceName(name);
400: url = this .getClass().getResource(name);
401: }
402: LOG.debug("Exit getResource( " + name + " ) = '" + url + "'");
403: return url;
404: }
405:
406: /**
407: * Loads a resource with the given name, using the correct ClassLoader.
408: * Does not swallow exceptions. See the JDK documentation on resources
409: * (they are pretty much files that are in the classpath of the
410: * classloader). Yes, this can be used successfully to get a class file
411: * (well, JDK 1.1 throws a SecurityException if this is attempted).
412: *
413: * @param name absolute referece to the expected resource.
414: * @return the resource name as an URL, which may possibly be
415: * <tt>null</tt>.
416: * @exception IOException if an I/O error occurs.
417: * @see java.lang.ClassLoader#getResource( String )
418: * @see java.lang.ClassLoader#getResourceAsStream( String )
419: */
420: public URL getSystemResource(String name) throws IOException {
421: LOG.debug("Enter getSystemResource( " + name + " )");
422: URL url = ClassLoader.getSystemResource(name);
423: LOG.debug("Exit getSystemResource( " + name + " ) = '" + url
424: + "'");
425: return url;
426: }
427:
428: /**
429: * Loads a resource with the given name, using the correct ClassLoader.
430: * Does not swallow exceptions. See the JDK documentation on resources
431: * (they are pretty much files that are in the classpath of the
432: * classloader). Yes, this can be used successfully to get a class file
433: * (well, JDK 1.1 throws a SecurityException if this is attempted).
434: *
435: * @param name absolute referece to the expected resource.
436: * @return the list of resource URLs, which may NOT be <tt>null</tt>
437: * (implementation ensures it is not null).
438: * @exception IOException if an I/O error occurs.
439: * @see java.lang.ClassLoader#getResource( String )
440: * @see java.lang.ClassLoader#getResources( String )
441: * @see java.lang.ClassLoader#getResourceAsStream( String )
442: */
443: public Enumeration getResources(String name) throws IOException {
444: return getResources(name, getClassLoader());
445: }
446:
447: /**
448: * Loads a resource with the given name, using the correct ClassLoader.
449: * Does not swallow exceptions. See the JDK documentation on resources
450: * (they are pretty much files that are in the classpath of the
451: * classloader). Yes, this can be used successfully to get a class file
452: * (well, JDK 1.1 throws a SecurityException if this is attempted).
453: *
454: * @param name absolute referece to the expected resource.
455: * @param cl the classloader to load the references from.
456: * @return a non-null list of resource URLs for the resource name.
457: * @exception IOException if an I/O error occurs.
458: * @see java.lang.ClassLoader#getResource( String )
459: * @see java.lang.ClassLoader#getResources( String )
460: * @see java.lang.ClassLoader#getResourceAsStream( String )
461: */
462: public Enumeration getResources( String name, ClassLoader cl )
463: throws IOException
464: {
465: Enumeration enum = null;
466: if (M_GET_RESOURCES != null && cl != null)
467: {
468: try
469: {
470: LOG.debug("Getting resources for "+name);
471: enum = (Enumeration)M_GET_RESOURCES.invoke( cl,
472: new Object[] { name } );
473: //LOG.debug("Found resources "+enum);
474: }
475: catch (java.lang.reflect.InvocationTargetException ite)
476: {
477: Throwable t = ite.getTargetException();
478: if (t instanceof IOException)
479: {
480: throw (IOException)t;
481: }
482: // else
483: LOG.info( "getResources( "+name+" ) threw exception.", t );
484:
485: enum = null;
486: }
487: catch (Exception e)
488: {
489: LOG.info( "invoke on getResources( "+name+
490: " ) threw exception.", e );
491:
492: enum = null;
493: }
494: }
495:
496:
497: // Yes, for invalid resources this will be incredibly inefficient.
498: // However, we want to be as robust as possible for those resource
499: // names that ARE valid. JDK 1.2+ can be sooo fickle.
500: if (enum == null || !enum.hasMoreElements())
501: {
502: LOG.debug("Resource enum is null or contains nothing.");
503:
504: // Try system resources next
505: enum = getSystemResources( name );
506:
507: if (enum == null || !enum.hasMoreElements())
508: {
509: // Try a single resource last
510: Vector v = new Vector();
511: URL url = getResource( name, cl );
512: if (url != null)
513: {
514: LOG.debug( "classloader getResource returned "+url );
515: v.addElement( url );
516: }
517: // else give up
518: enum = v.elements();
519: }
520: }
521:
522: return enum;
523: }
524:
525: /**
526: * Get the resource associated with the given name from the System
527: * classloader. This will never return <tt>null</tt>.
528: *
529: * @param name absolute referece to the expected resource.
530: * @return a non-null list of URLs matching the resource.
531: * @exception IOException if an I/O error occurs.
532: * @see java.lang.ClassLoader#getResource( String )
533: * @see java.lang.ClassLoader#getResources( String )
534: * @see java.lang.ClassLoader#getResourceAsStream( String )
535: */
536: public Enumeration getSystemResources( String name )
537: throws IOException
538: {
539: Enumeration enum = null;
540: if (M_GET_SYSTEM_RESOURCES != null)
541: {
542: try
543: {
544: LOG.debug("Getting system resources for "+name);
545: // static method
546: enum = (Enumeration)M_GET_SYSTEM_RESOURCES.invoke( null,
547: new Object[] { name } );
548: //LOG.debug("Found system resources "+enum);
549: }
550: catch (java.lang.reflect.InvocationTargetException ite)
551: {
552: Throwable t = ite.getTargetException();
553: if (t instanceof IOException)
554: {
555: throw (IOException)t;
556: }
557: // else
558: LOG.info( "getSystemResources( "+name+
559: " ) threw exception.", t );
560:
561: enum = null;
562: }
563: catch (Exception e)
564: {
565: LOG.info( "invoke on getResources( "+name+
566: " ) threw exception.", e );
567:
568: enum = null;
569: }
570: }
571:
572:
573: // Yes, for invalid resources this will be incredibly inefficient.
574: // However, we want to be as robust as possible for those resource
575: // names that ARE valid.
576: if (enum == null || !enum.hasMoreElements())
577: {
578: LOG.debug("Resource enum is null or contains nothing.");
579: Vector v = new Vector();
580: URL url = getSystemResource( name );
581: if (url != null)
582: {
583: LOG.debug( "classloader getSystemResource returned "+url );
584: v.addElement( url );
585: }
586: // else give up
587:
588: enum = v.elements();
589: }
590:
591: return enum;
592: }
593:
594: //----------------------------
595: // Protected methods
596:
597: /**
598: * Gets the correct class loader. May return null.
599: *
600: * @return the ClassLoader
601: */
602: protected ClassLoader getClassLoader() {
603: ClassLoader cl = this .classLoader;
604: if (cl == null) {
605: cl = getThreadClassLoader(Thread.currentThread());
606: if (cl == null) {
607: // JDK 1.1 may return NULL here.
608: cl = this .getClass().getClassLoader();
609: }
610: }
611: return cl;
612: }
613:
614: /**
615: * Loads a class with the given name, using the correct ClassLoader.
616: * Does not swallow exceptions.
617: *
618: * @exception ClassNotFoundException if the class name is not known by the
619: * class loader.
620: * @exception LinkageError if there was a basic class loader error.
621: * @exception IllegalArgumentException if the class doesn't smell right to
622: * JDK 1.1.
623: */
624: protected Class loadClass(String name)
625: throws ClassNotFoundException, LinkageError,
626: IllegalArgumentException {
627: ClassLoader cl = getClassLoader();
628: Class c = null;
629: if (name != null) {
630: if (cl == null) {
631: c = Class.forName(name);
632: } else {
633: c = cl.loadClass(name);
634: }
635: }
636: return c;
637: }
638:
639: /**
640: * Use reflection to get the thread (context) class loader.
641: */
642: protected static ClassLoader getThreadClassLoader(Thread t) {
643: ClassLoader cl = null;
644: if (M_GET_CONTEXT_CLASSLOADER != null) {
645: try {
646: cl = (ClassLoader) M_GET_CONTEXT_CLASSLOADER.invoke(t,
647: null);
648: } catch (Exception e) {
649: cl = null;
650: }
651: }
652: return cl;
653: }
654:
655: /**
656: *
657: */
658: protected static Method discoverContextClassloaderMethod() {
659: Method m;
660: try {
661: Class c = Thread.class;
662: m = c.getDeclaredMethod("getContextClassLoader",
663: new Class[0]);
664: } catch (Exception e) {
665: // discovery method: exception is expected where this is not
666: // supoorted.
667: // LOG.info( "discoverContextClassloaderMethod() threw exception.",
668: // e );
669:
670: m = null;
671: }
672: return m;
673: }
674:
675: /**
676: *
677: */
678: protected static Method discoverGetResourcesMethod() {
679: Method m;
680: try {
681: Class c = ClassLoader.class;
682: m = c.getDeclaredMethod("getResources",
683: new Class[] { String.class });
684: } catch (Exception e) {
685: // discovery method: exception is expected where this is not
686: // supoorted.
687: // LOG.info( "discoverGetResourcesMethod() threw exception.",
688: // e );
689:
690: m = null;
691: }
692: return m;
693: }
694:
695: /**
696: *
697: */
698: protected static Method discoverGetSystemResourcesMethod() {
699: Method m;
700: try {
701: Class c = ClassLoader.class;
702: m = c.getDeclaredMethod("getSystemResources",
703: new Class[] { String.class });
704: } catch (Exception e) {
705: // discovery method: exception is expected where this is not
706: // supoorted.
707: // LOG.info( "discoverGetSystemResourcesMethod() threw exception.",
708: // e );
709:
710: m = null;
711: }
712: return m;
713: }
714:
715: /**
716: *
717: */
718: protected String getAbsoluteResourceName(String name) {
719: // Using 'Class' getResourceAsStream, which is relative to its
720: // package, whereas the ClassLoader is an absolute name. So,
721: // ensure that the name is absolute to be compatible.
722: if (name != null && name.length() > 0 && name.charAt(0) != '/') {
723: name = '/' + name;
724: }
725: return name;
726: }
727: }
|