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