1 /**
2  * The utillib library.
3  * More information is available at http://www.jinchess.com/.
4  * Copyright (C) 2003 Alexander Maryanovsky.
5  * All rights reserved.
6  *
7  * The utillib library is free software; you can redistribute
8  * it and/or modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * The utillib library is distributed in the hope that it will
13  * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with utillib library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 package free.util;
23 
24 import java.io.InputStream;
25 import java.io.IOException;
26 import java.net.URL;
27 import java.util.Hashtable;
28 import free.util.IOUtilities;
29 
30 
31 /**
32  * A class loader with a parent, to which loading is delegated if the class or
33  * resource can't be found. This class isn't needed with JDK1.2 which already
34  * has this functionality. As an additional feature, this class uses a Hashtable
35  * to look up already loaded classes, so any subclasses needn't do this.
36  */
37 
38 public abstract class ChildClassLoader extends ClassLoader{
39 
40 
41 
42   /**
43    * The parent classloader. May be null.
44    */
45 
46   private final ChildClassLoader parent;
47 
48 
49 
50   /**
51    * Maps class names to already loaded classes.
52    */
53 
54   private final Hashtable namesToClasses = new Hashtable();
55 
56 
57 
58   /**
59    * Creates a new <code>ChildClassLoader</code> with the specified parent. The
60    * parent may be <code>null</code>.
61    */
62 
ChildClassLoader(ChildClassLoader parent)63   public ChildClassLoader(ChildClassLoader parent){
64     this.parent = parent;
65   }
66 
67 
68 
69   /**
70    * Creates a new <code>ChildClassLoader</code> with no parent.
71    */
72 
ChildClassLoader()73   public ChildClassLoader(){
74     this(null);
75   }
76 
77 
78 
79   /**
80    * Returns the parent classloader.
81    */
82 
getParentClassLoader()83   public ChildClassLoader getParentClassLoader(){
84     return parent;
85   }
86 
87 
88 
89   /**
90    * Loads and optionally resolves the class with the specified name. If this
91    * classloader can't find the specified class, the parent is asked to load it.
92    */
93 
loadClass(String name, boolean resolve)94   public final synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException{
95     Class c = (Class)namesToClasses.get(name);
96     if (c != null)
97       return c;
98 
99     c = loadClassImpl(name, resolve);
100     if (c == null){
101       if (parent == null)
102         throw new ClassNotFoundException(name);
103       else
104         c = parent.loadClass(name, resolve);
105     }
106 
107     namesToClasses.put(name, c);
108     return c;
109   }
110 
111 
112 
113   /**
114    * Returns an <code>InputStream</code> for reading the resource with the
115    * specified name. If this classloader can't find the resource, the parent
116    * is asked to find it.
117    */
118 
getResourceAsStream(String name)119   public final InputStream getResourceAsStream(String name){
120     InputStream in = getResourceAsStreamImpl(name);
121     return in != null ? in : (parent == null ? null : parent.getResourceAsStream(name));
122   }
123 
124 
125 
126   /**
127    * Returns a <code>URL</code> pointing to the resource with the specified
128    * name. If this classloader can't find the resource, the parent is asked to
129    * find it.
130    */
131 
getResource(String name)132   public final URL getResource(String name){
133     URL url = getResourceImpl(name);
134     return url != null ? url : (parent == null ? null : parent.getResource(name));
135   }
136 
137 
138 
139   /**
140    * Loads the class data for the specified class name. The default
141    * implementation loads the class data via
142    * <code>getResourceAsStreamImpl</code>
143    */
144 
loadClassData(String name)145   protected byte [] loadClassData(String name) throws IOException{
146     String resourceName = name.replace('.', '/') + ".class";
147     InputStream in = getResourceAsStreamImpl(resourceName);
148     if (in == null)
149       return null;
150 
151     return IOUtilities.readToEnd(in);
152   }
153 
154 
155 
156   /**
157    * Loads the class with the specified name and optionally resolves it.
158    * The default implementation first tries to obtain the class via
159    * <code>findSystemClass</code> and if that fails, loads the class via
160    * <code>loadClassData</code>.
161    */
162 
loadClassImpl(String name, boolean resolve)163   protected Class loadClassImpl(String name, boolean resolve){
164     try{
165       Class c = null;
166       try{
167         c = findSystemClass(name);
168       } catch (ClassNotFoundException e){}
169 
170       if (c == null){
171         byte [] classData = loadClassData(name);
172         if (classData == null)
173           return null;
174 
175         c = defineClass(name, classData, 0, classData.length);
176       }
177 
178       if (resolve)
179         resolveClass(c);
180 
181       return c;
182     } catch (IOException e){
183         return null;
184       }
185   }
186 
187 
188 
189   /**
190    * Returns an <code>InputStream</code> for reading the resource with the
191    * specified name.
192    */
193 
getResourceAsStreamImpl(String name)194   protected abstract InputStream getResourceAsStreamImpl(String name);
195 
196 
197 
198   /**
199    * Returns a <code>URL</code> pointing to the resource with the specified
200    * name.
201    */
202 
getResourceImpl(String name)203   protected abstract URL getResourceImpl(String name);
204 
205 
206 
207 }
208