KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > groboutils > util > classes > v1 > ClassUtil


1 /*
2  * @(#)ClassUtil.java 0.9.0 11/13/2000 - 14:06:34
3  *
4  * Copyright (C) 2000,2002-2003 Matt Albrecht
5  * groboclown@users.sourceforge.net
6  * http://groboutils.sourceforge.net
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  */

26
27 package net.sourceforge.groboutils.util.classes.v1;
28
29 import java.util.Hashtable JavaDoc;
30
31
32
33
34 /**
35  * Utility class for loading classes and creating instances. It decides
36  * which JDK version to use as the loader. Class instances are put
37  * into a Hashtable, based on URL and classname. When the Java-Doc defines
38  * a <tt>jarName</tt>, as in {@link #getClass( String, String )}, the
39  * <tt>jarName</tt> may be a filename loadable from the {@link java.io.File}
40  * class, or a proper URL loadable from the {@link java.net.URL} class.
41  * If the <tt>jarName</tt> does not have a protocol, then it is assumed to
42  * be a file, otherwise, it is used as a URL.
43  * <P>
44  * Note that this class is not thread safe. It is assumed that applications
45  * will use the ClassUtil only during initialization times, since dynamic
46  * class loading can be very expensive. If you need thread safety, then you
47  * will need to ensure that either all class loading is done in a single thread,
48  * or that your application properly <tt>synchronize</tt>s the method calls.
49  * <P>
50  * Update v0.9.1: the constructor will now check for jdk2 first like before,
51  * but now if it is not found, it will try to use jdk0 compatibility - before,
52  * it would just fail out. This allows the libraries to be repackaged to
53  * contain only the jdk0 classes if so desired.
54  *
55  * @author Matt Albrecht <a HREF="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
56  * @version $Date: 2003/02/10 22:52:36 $
57  * @since November 13, 2000 (GroboUtils Alpha 0.9.0)
58  */

59 public class ClassUtil
60 {
61     //----------------------------
62
// Public data
63

64     //----------------------------
65
// Private data
66

67     /**
68      * Subclasses must instantiate themselves in this variable in their
69      * static initialization block, and overload the {@link #getInstance()}
70      * static method.
71      */

72     protected static ClassUtil s_instance = new ClassUtil();
73     
74     private IUrlClassLoader classLoader = null;
75     private Hashtable JavaDoc classHash = new Hashtable JavaDoc();
76     
77     //----------------------------
78
// constructors
79

80     /**
81      * Default constructor - made protected so
82      * users won't instantiate the utility
83      */

84     protected ClassUtil()
85     {
86         // detect which JDK we're using, and from that use the correct
87
// IUrlClassLoader instance.
88

89         if (isJdk2Compatible())
90         {
91             this.classLoader = (IUrlClassLoader)createObject(
92                 getClassPackage( ClassUtil.class ) + ".jdk2.UrlClassLoader" );
93         }
94         if (this.classLoader == null)
95         {
96             this.classLoader = (IUrlClassLoader)createObject(
97                 getClassPackage( ClassUtil.class ) + ".jdk0.UrlClassLoader" );
98             if (this.classLoader == null)
99             {
100                 throw new IllegalStateException JavaDoc(
101                     "There was an error loading a class loader." );
102             }
103         }
104     }
105     
106     
107     //----------------------------
108
// Public Static methods
109

110     
111     /**
112      * Retrieve the shared instance of the utility class.
113      *
114      * @return the utility instance
115      */

116     public static ClassUtil getInstance()
117     {
118         // Due to threading issues, the instance is created
119
// in the static initialization block.
120

121         return s_instance;
122     }
123      
124      
125      
126     //----------------------------
127
// Public methods
128

129     
130     /**
131      * Call this to flush out the cache. The cache may be huge, depending
132      * on the Jar files loaded, as well as the Class instances. This
133      * should be called whenever a mass class instantiation process is
134      * finished.
135      */

136     public void flush()
137     {
138         this.classHash = new Hashtable JavaDoc();
139         this.classLoader.flush();
140     }
141     
142      
143     /**
144      * Either finds or loads from cache the given class, using the
145      * default class loader.
146      *
147      * @param name the name of the class to load.
148      * @return the discovered Class, or <tt>null</tt> if it could not be found.
149      * @see #getClass( String, String )
150      */

151     public Class JavaDoc getClass( String JavaDoc name )
152     {
153         return getClass( name, null );
154     }
155     
156     
157     /**
158      * Either finds or loads from cache the given class.
159      *
160      * @param name the name of the class to load.
161      * @param jarName the URL to load the class from - it may be <tt>null</tt>.
162      * @return the discovered Class, or <tt>null</tt> if it could not be found.
163      * @see #getClass( String )
164      */

165     public Class JavaDoc getClass( String JavaDoc name, String JavaDoc jarName )
166     {
167         String JavaDoc hashName = getClassHashName( name, jarName );
168         Class JavaDoc c = (Class JavaDoc)classHash.get( hashName );
169         if (c == null)
170         {
171             c = loadClass( name, jarName );
172             if (c != null)
173             {
174                 classHash.put( hashName, c );
175             }
176         }
177         return c;
178     }
179     
180     
181     /**
182      * Creates a new instance of the class with the given <tt>className</tt>
183      * using the default constructor. If there was an error during the
184      * creation, such as the class was not found, the class does not have
185      * a default constructor, or the constructor threw an exception, then
186      * <tt>null</tt> is returned.
187      *
188      * @param className the name of the class to create an instance.
189      * @return the new instance, or <tt>null</tt> if there was a problem.
190      * @see #getClass( String )
191      * @see #createObject( String, String )
192      */

193     public Object JavaDoc createObject( String JavaDoc className )
194     {
195         return createObject( className, null );
196     }
197     
198     
199     /**
200      * Creates a new instance of the class with the given <tt>className</tt>
201      * using the default constructor, from the given URL. If there was an
202      * error during the creation, such as the class was not found, the class
203      * does not have a default constructor, or the constructor threw an
204      * exception, then <tt>null</tt> is returned.
205      *
206      * @param className the name of the class to create an instance.
207      * @param jarName the URL to load the class from - it may be <tt>null</tt>.
208      * @return the new instance, or <tt>null</tt> if there was a problem.
209      * @see #getClass( String, String )
210      * @see #createObject( String )
211      */

212     public Object JavaDoc createObject( String JavaDoc className, String JavaDoc jarName )
213     {
214         return createObject( getClass( className, jarName ) );
215     }
216     
217     
218     /**
219      * Creates an Object from the given Class, using its default constructor.
220      * All creation exceptions are swallowed. If the object could not
221      * be created, then <tt>null</tt> is returned.
222      *
223      * @param c the Class object from which a new instance will be created
224      * using its default constructor.
225      * @return the instantiated object, or <tt>null</tt> if <tt>c</tt> is
226      * <tt>null</tt>, or if there was an error during initialization.
227      */

228     public Object JavaDoc createObject( Class JavaDoc c )
229     {
230         if (c == null) return null;
231         
232         Object JavaDoc obj = null;
233         try
234         {
235             obj = c.newInstance();
236         }
237         catch (InstantiationException JavaDoc ie)
238         {
239             System.out.println("Could not instantiate "+c.getName()+
240                 ": "+ie.getMessage());
241             obj = null;
242         }
243         catch (IllegalAccessException JavaDoc iae)
244         {
245             System.out.println("Could not instantiate "+c.getName()+
246                 ": "+iae.getMessage());
247             obj = null;
248         }
249         catch (NoSuchMethodError JavaDoc nsme)
250         {
251             System.out.println("Could not instantiate "+c.getName()+
252                 ": "+nsme.getMessage());
253             obj = null;
254         }
255         return obj;
256     }
257     
258     
259     /**
260      * Checks if the current JVM version is 1.2 compatible. We check by
261      * seeing if <tt>java.net.URLClassLoader</tt> exists.
262      *
263      * @return <tt>true</tt> if {@link java.net.URLClassLoader} exists
264      * in the classpath, or <tt>false</tt> otherwise.
265      */

266     public boolean isJdk2Compatible()
267     {
268         return (getClass( "java.net.URLClassLoader" ) != null);
269     }
270     
271     
272     /**
273      * Discovers the package name for the given class. The package name
274      * will not have a final '.'.
275      *
276      * @param c the class to find the package name.
277      * @return the package name, or <tt>null</tt> if <tt>c</tt> is
278      * <tt>null</tt>.
279      */

280     public String JavaDoc getClassPackage( Class JavaDoc c )
281     {
282         if (c == null)
283         {
284             return null;
285         }
286         String JavaDoc fullname = c.getName();
287         int pos = fullname.lastIndexOf( '.' );
288         if (pos < 0)
289         {
290             // no package
291
return "";
292         }
293         
294         // else, extract the pacakge name.
295
return fullname.substring( 0, pos );
296     }
297      
298      
299     //----------------------------
300
// Protected methods
301

302     
303     /**
304      * Creates the name of the class for the hashtable lookup, which is
305      * a junction of the jar name and the class name. It allows for multiple
306      * classes with the same name.
307      *
308      * @param name the class name
309      * @param jarName the jar name - may be <tt>null</tt>.
310      * @return the name for the hashtable lookup.
311      */

312     protected String JavaDoc getClassHashName( String JavaDoc name, String JavaDoc jarName )
313     {
314         if (jarName == null)
315         {
316             jarName = "<null>";
317         }
318         StringBuffer JavaDoc sb = new StringBuffer JavaDoc( jarName );
319         sb.append( ';' );
320         sb.append( name );
321         return new String JavaDoc( sb );
322     }
323     
324     
325     /**
326      * Attempts to load the class from the current classpath if <tt>baseJar</tt>
327      * is <tt>null</tt>, or from the appropriate class loader if it is not
328      * <tt>null</tt>. If the class is not found, then this returns
329      * <tt>null</tt>. This never throws an exception.
330      *
331      * @param className name of the class to load
332      * @param baseJar the URL file to load the class from - may be
333      * <tt>null</tt>.
334      * @return the Class instance, or <tt>null</tt> if it was not found.
335      */

336     protected Class JavaDoc loadClass( String JavaDoc className, String JavaDoc baseJar )
337     {
338         Class JavaDoc c;
339         
340         try
341         {
342             if (baseJar == null || baseJar.length() <= 0)
343             {
344                 try
345                 {
346                     c = Class.forName( className );
347                 }
348                 catch (ClassNotFoundException JavaDoc cnfe)
349                 {
350 // System.out.println("Class "+className+" not found");
351
c = null;
352                 }
353             }
354             else
355             {
356                 c = this.classLoader.loadClass( className, baseJar );
357             }
358         }
359         catch (Throwable JavaDoc t)
360         {
361             // probably a NoClassDefFoundError
362
c = null;
363         }
364         return c;
365     }
366     
367     
368     
369     //----------------------------
370
// Private methods
371
}
372  
373
Popular Tags