1 |
/* java.lang.ClassLoader |
/* ClassLoader.java -- responsible for loading classes into the VM |
2 |
Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc. |
Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
7 |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
8 |
the Free Software Foundation; either version 2, or (at your option) |
the Free Software Foundation; either version 2, or (at your option) |
9 |
any later version. |
any later version. |
10 |
|
|
11 |
GNU Classpath is distributed in the hope that it will be useful, but |
GNU Classpath is distributed in the hope that it will be useful, but |
12 |
WITHOUT ANY WARRANTY; without even the implied warranty of |
WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
48 |
import gnu.java.util.EmptyEnumeration; |
import gnu.java.util.EmptyEnumeration; |
49 |
|
|
50 |
/** |
/** |
51 |
** The ClassLoader is a way of customizing the way Java |
* The ClassLoader is a way of customizing the way Java gets its classes |
52 |
** gets its classes and loads them into memory. The |
* and loads them into memory. The verifier and other standard Java things |
53 |
** verifier and other standard Java things still run, but |
* still run, but the ClassLoader is allowed great flexibility in determining |
54 |
** the ClassLoader is allowed great flexibility in |
* where to get the classfiles and when to load and resolve them. For that |
55 |
** determining where to get the classfiles and when to |
* matter, a custom ClassLoader can perform on-the-fly code generation or |
56 |
** load and resolve them. |
* modification! |
57 |
** |
* |
58 |
** XXX - Not all support has been written for the new 1.2 methods yet! |
* XXX - Not all support has been written for the new 1.2 methods yet! |
59 |
** |
* |
60 |
** <p> |
* <p>Every classloader has a parent classloader that is consulted before |
61 |
** Every classloader has a parent classloader that is consulted before |
* the 'child' classloader when classes or resources should be loaded. |
62 |
** the 'child' classloader when classes or resources should be loaded. |
* This is done to make sure that classes can be loaded from an hierarchy of |
63 |
** This is done to make sure that classes can be loaded from an hierarchy of |
* multiple classloaders and classloaders do not accidentially redefine |
64 |
** multiple classloaders and classloaders do not accidentially redefine |
* already loaded classes by classloaders higher in the hierarchy. |
65 |
** already loaded classes by classloaders higher in the hierarchy. |
* |
66 |
** <p> |
* <p>The grandparent of all classloaders is the bootstrap classloader, which |
67 |
** The grandparent of all classloaders is the bootstrap classloader. |
* loads all the standard system classes as implemented by GNU Classpath. The |
68 |
** It is one of two special classloaders. |
* other special classloader is the system classloader (also called |
69 |
** The bootstrap classloader loads all the standard system classes as |
* application classloader) that loads all classes from the CLASSPATH |
70 |
** implemented by GNU Classpath. The other special classloader is the |
* (<code>java.class.path</code> system property). The system classloader |
71 |
** system classloader (also called application classloader) that loads |
* is responsible for finding the application classes from the classpath, |
72 |
** all classes from the classpath (<code>java.class.path</code> system |
* and delegates all requests for the standard library classes to its parent |
73 |
** property). The system classloader is responsible for finding the |
* the bootstrap classloader. Most programs will load all their classes |
74 |
** application classes from the classpath, and delegates all requests for |
* through the system classloaders. |
75 |
** the standard library classes to its parent the bootstrap classloader. |
* |
76 |
** Most programs will load all their classes through the system classloaders. |
* <p>The bootstrap classloader in GNU Classpath is implemented as a couple of |
77 |
** <p> |
* static (native) methods on the package private class |
78 |
** The bootstrap classloader in GNU Classpath is implemented as a couple of |
* <code>java.lang.VMClassLoader</code>, the system classloader is an |
79 |
** static (native) methods on the package private class |
* instance of <code>gnu.java.lang.SystemClassloader</code> |
80 |
** <code>java.lang.VMClassLoader</code>, the system classloader is an |
* (which is a subclass of <code>java.net.URLClassLoader</code>). |
81 |
** instance of <code>gnu.java.lang.SystemClassloader</code> |
* |
82 |
** (which is a subclass of <code>java.net.URLClassLoader</code>). |
* <p>Users of a <code>ClassLoader</code> will normally just use the methods |
83 |
** <p> |
* <ul> |
84 |
** Users of a <code>ClassLoader</code> will normally just use the methods |
* <li> <code>loadClass()</code> to load a class.</li> |
85 |
** <ul> |
* <li> <code>getResource()</code> or <code>getResourceAsStream()</code> |
86 |
** <li> <code>loadClass()</code> to load a class. |
* to access a resource.</li> |
87 |
** <li> <code>getResource()</code> or <code>getResourceAsStream()</code> |
* <li> <code>getResources()</code> to get an Enumeration of URLs to all |
88 |
** to access a resource. |
* the resources provided by the classloader and its parents with the |
89 |
** <li> <code>getResources()</code> to get an Enumeration of URLs to all |
* same name.</li> |
90 |
** the resources provided by the classloader and its parents with the same |
* </ul> |
91 |
** name. |
* |
92 |
** </ul> |
* <p>Subclasses should implement the methods |
93 |
** <p> |
* <ul> |
94 |
** Subclasses should implement the methods |
* <li> <code>findClass()</code> which is called by <code>loadClass()</code> |
95 |
** <ul> |
* when the parent classloader cannot provide a named class.</li> |
96 |
** <li> <code>findClass()</code> which is called by <code>loadClass()</code> |
* <li> <code>findResource()</code> which is called by |
97 |
** when the parent classloader cannot provide a named class. |
* <code>getResource()</code> when the parent classloader cannot provide |
98 |
** <li> <code>findResource()</code> which is called by |
* a named resource.</li> |
99 |
** <code>getResource()</code> when the parent classloader cannot provide |
* <li> <code>findResources()</code> which is called by |
100 |
** a named resource. |
* <code>getResource()</code> to combine all the resources with the |
101 |
** <li> <code>findResources()</code> which is called by |
* same name from the classloader and its parents.</li> |
102 |
** <code>getResource()</code> to combine all the resources with the same name |
* <li> <code>findLibrary()</code> which is called by |
103 |
** from the classloader and its parents. |
* <code>Runtime.loadLibrary()</code> when a class defined by the |
104 |
** <li> <code>findLibrary()</code> which is called by |
* classloader wants to load a native library.</li> |
105 |
** <code>Runtime.loadLibrary()</code> when a class defined by the classloader |
* </ul> |
106 |
** wants to load a native library. |
* |
107 |
** </ul> |
* @author John Keiser |
108 |
** |
* @author Mark Wielaard |
109 |
** @author John Keiser |
* @author Eric Blake <ebb9@email.byu.edu> |
110 |
** @author Mark Wielaard |
* @see Class |
111 |
** @version 1.1.99, Jan 2000 |
* @since 1.0 |
112 |
** @since JDK1.0 |
* @status still missing 1.4 functionality |
113 |
**/ |
*/ |
114 |
|
public abstract class ClassLoader |
115 |
public abstract class ClassLoader { |
{ |
116 |
/* Each instance gets a list of these. */ |
/** All classes loaded by this classloader. */ |
117 |
private Hashtable loadedClasses = new Hashtable(); |
private Hashtable loadedClasses = new Hashtable(); |
118 |
|
|
119 |
/* Each instance gets a list of these. */ |
/** All packages defined by this classloader. */ |
120 |
private Hashtable definedPackages = new Hashtable(); |
private Hashtable definedPackages = new Hashtable(); |
121 |
|
|
122 |
/* The classloader that is consulted before this classloader. |
/** |
123 |
if null then the parent is the bootstrap classloader. */ |
* The classloader that is consulted before this classloader. |
124 |
private final ClassLoader parent; |
* If null then the parent is the bootstrap classloader. |
125 |
|
*/ |
126 |
/* System/Application classloader gnu.java.lang.SystemClassLoader. */ |
private final ClassLoader parent; |
127 |
static final ClassLoader systemClassLoader |
|
128 |
= null; // XXX = SystemClassLoader.getInstance(); |
/** |
129 |
|
* System/Application classloader gnu.java.lang.SystemClassLoader. |
130 |
/** Create a new ClassLoader with as parent the system classloader. |
* Due to bootstrapping issues, the VM must modify this field. |
131 |
** @exception SecurityException if you do not have permission |
*/ |
132 |
** to create a ClassLoader. |
static final ClassLoader systemClassLoader |
133 |
**/ |
= null; // XXX = SystemClassLoader.getInstance(); |
134 |
protected ClassLoader() throws SecurityException { |
|
135 |
this(systemClassLoader); |
/** |
136 |
} |
* The desired assertion status of classes loaded by this loader, if not |
137 |
|
* overridden by package or class instructions. |
138 |
/** Create a new ClassLoader with the specified parent. |
* @XXX Implement for 1.4 compatibility. |
139 |
** The parent will be consulted when a class or resource is |
// Package visible for use by Class. |
140 |
** requested through <code>loadClass()</code> or |
boolean defaultAssertionStatus = VMClassLoader.defaultAssertionStatus(); |
141 |
** <code>getResource()</code>. Only when the parent classloader |
*/ |
142 |
** cannot provide the requested class or resource the |
|
143 |
** <code>findClass()</code> or <code>findResource()</code> method |
/** |
144 |
** of this classloader will be called. |
* The command-line state of the package assertion status overrides. This |
145 |
** |
* map is never modified, so it does not need to be synchronized. |
146 |
** @param parent the classloader that should be consulted before |
* @XXX Implement for 1.4 compatibility. |
147 |
** this classloader. Use <code>null</code> to specify the bootstrap |
// Package visible for use by Class. |
148 |
** classloader. |
static final Map systemPackageAssertionStatus |
149 |
** @exception SecurityException if you do not have permission |
= VMClassLoader.packageAssertionStatus(); |
150 |
** to create a ClassLoader. |
*/ |
151 |
** |
|
152 |
** @since 1.2 |
/** |
153 |
**/ |
* The map of package assertion status overrides, or null if no package |
154 |
protected ClassLoader(ClassLoader parent) { |
* overrides have been specified yet. The values of the map should be |
155 |
// May we create a new classloader? |
* Boolean.TRUE or Boolean.FALSE, and the unnamed package is represented |
156 |
SecurityManager sm = System.getSecurityManager(); |
* by the null key. This map must be synchronized on this instance. |
157 |
if (sm != null) |
* @XXX Implement for 1.4 compatibility. |
158 |
sm.checkCreateClassLoader(); |
// Package visible for use by Class. |
159 |
|
Map packageAssertionStatus; |
160 |
this.parent = parent; |
*/ |
161 |
} |
|
162 |
|
/** |
163 |
/** Load a class using this ClassLoader or its parent, |
* The command-line state of the class assertion status overrides. This |
164 |
** without resolving it. Calls <code>loadClass(name, false)</code>. |
* map is never modified, so it does not need to be synchronized. |
165 |
** <p> |
* @XXX Implement for 1.4 compatibility. |
166 |
** Subclasses should not override this method but should override |
// Package visible for use by Class. |
167 |
** <code>findClass()</code> which is called by this method. |
static final Map systemClassAssertionStatus |
168 |
** |
= VMClassLoader.classAssertionStatus(); |
169 |
** @param name the name of the class relative to this ClassLoader. |
*/ |
170 |
** @exception ClassNotFoundException if the class cannot be found to |
|
171 |
** be loaded. |
/** |
172 |
** @return the loaded class. |
* The map of class assertion status overrides, or null if no class |
173 |
**/ |
* overrides have been specified yet. The values of the map should be |
174 |
public Class loadClass(String name) throws ClassNotFoundException { |
* Boolean.TRUE or Boolean.FALSE. This map must be synchronized on this |
175 |
return loadClass(name,false); |
* instance. |
176 |
} |
* @XXX Implement for 1.4 compatibility. |
177 |
|
// Package visible for use by Class. |
178 |
/** Load a class using this ClassLoader or its parent, |
Map classAssertionStatus; |
179 |
** possibly resolving it as well using <code>resolveClass()</code>. |
*/ |
180 |
** It first tries to find out if the class has already been loaded |
|
181 |
** through this classloader by calling <code>findLoadedClass()</code>. |
/** |
182 |
** Then it calls <code>loadClass()</code> on the parent classloader |
* Create a new ClassLoader with as parent the system classloader. There |
183 |
** (or when there is no parent on the bootstrap classloader). |
* may be a security check for <code>checkCreateClassLoader</code>. |
184 |
** When the parent could not load the class it tries to create |
* |
185 |
** a new class by calling <code>findClass()</code>. Finally when |
* @throws SecurityException if the security check fails |
186 |
** <code>resolve</code> is <code>true</code> it also calls |
*/ |
187 |
** <code>resolveClass()</code> on the newly loaded class. |
protected ClassLoader() throws SecurityException |
188 |
** <p> |
{ |
189 |
** Subclasses should not override this method but should override |
//XXX This should be this(getSystemClassLoader()); |
190 |
** <code>findClass()</code> which is called by this method. |
this(systemClassLoader); |
191 |
** |
} |
192 |
** @param name the fully qualified name of the class to load. |
|
193 |
** @param resolve whether or not to resolve the class. |
/** |
194 |
** @exception ClassNotFoundException if the class cannot be found to |
* Create a new ClassLoader with the specified parent. The parent will |
195 |
** be loaded. |
* be consulted when a class or resource is requested through |
196 |
** @return the loaded class. |
* <code>loadClass()</code> or <code>getResource()</code>. Only when the |
197 |
**/ |
* parent classloader cannot provide the requested class or resource the |
198 |
|
* <code>findClass()</code> or <code>findResource()</code> method |
199 |
|
* of this classloader will be called. There may be a security check for |
200 |
|
* <code>checkCreateClassLoader</code>. |
201 |
|
* |
202 |
|
* @param parent the classloader's parent, or null for the bootstrap |
203 |
|
* classloader |
204 |
|
* @throws SecurityException if the security check fails |
205 |
|
* @since 1.2 |
206 |
|
*/ |
207 |
|
protected ClassLoader(ClassLoader parent) |
208 |
|
{ |
209 |
|
// May we create a new classloader? |
210 |
|
SecurityManager sm = System.getSecurityManager(); |
211 |
|
if (sm != null) |
212 |
|
sm.checkCreateClassLoader(); |
213 |
|
this.parent = parent; |
214 |
|
} |
215 |
|
|
216 |
|
/** |
217 |
|
* Load a class using this ClassLoader or its parent, without resolving |
218 |
|
* it. Calls <code>loadClass(name, false)</code>. |
219 |
|
* |
220 |
|
* <p>Subclasses should not override this method but should override |
221 |
|
* <code>findClass()</code> which is called by this method. |
222 |
|
* |
223 |
|
* @param name the name of the class relative to this ClassLoader |
224 |
|
* @return the loaded class |
225 |
|
* @throws ClassNotFoundException if the class cannot be found |
226 |
|
*/ |
227 |
|
public Class loadClass(String name) throws ClassNotFoundException |
228 |
|
{ |
229 |
|
return loadClass(name, false); |
230 |
|
} |
231 |
|
|
232 |
|
/** |
233 |
|
* Load a class using this ClassLoader or its parent, possibly resolving |
234 |
|
* it as well using <code>resolveClass()</code>. It first tries to find |
235 |
|
* out if the class has already been loaded through this classloader by |
236 |
|
* calling <code>findLoadedClass()</code>. Then it calls |
237 |
|
* <code>loadClass()</code> on the parent classloader (or when there is |
238 |
|
* no parent on the bootstrap classloader). When the parent could not load |
239 |
|
* the class it tries to create a new class by calling |
240 |
|
* <code>findClass()</code>. Finally when <code>resolve</code> is |
241 |
|
* <code>true</code> it also calls <code>resolveClass()</code> on the |
242 |
|
* newly loaded class. |
243 |
|
* |
244 |
|
* <p>Subclasses should not override this method but should override |
245 |
|
* <code>findClass()</code> which is called by this method. |
246 |
|
* |
247 |
|
* @param name the fully qualified name of the class to load |
248 |
|
* @param resolve whether or not to resolve the class |
249 |
|
* @return the loaded class |
250 |
|
* @throws ClassNotFoundException if the class cannot be found |
251 |
|
*/ |
252 |
protected synchronized Class loadClass(String name, boolean resolve) |
protected synchronized Class loadClass(String name, boolean resolve) |
253 |
throws ClassNotFoundException |
throws ClassNotFoundException |
254 |
{ |
{ |
255 |
// Have we already loaded this class? |
// Have we already loaded this class? |
256 |
Class c = findLoadedClass(name); |
Class c = findLoadedClass(name); |
257 |
if (c != null) |
if (c != null) |
|
return c; |
|
|
|
|
|
// Can the class be loaded by one of our parent? |
|
|
try { |
|
|
if (parent == null) |
|
|
// XXX - use the bootstrap classloader |
|
|
// return VMClassLoader.loadClass(name, resolve); |
|
|
return findSystemClass(name); |
|
|
else |
|
|
return parent.loadClass(name, resolve); |
|
|
} catch (ClassNotFoundException e) { /* ignore use findClass() */ } |
|
|
|
|
|
// Still not found, we have to do it ourselfs. |
|
|
c = findClass(name); |
|
|
|
|
|
// resolve if necessary |
|
|
if (resolve) |
|
|
resolveClass(c); |
|
|
|
|
258 |
return c; |
return c; |
|
} |
|
|
|
|
|
/** Get the URL to a resource using this classloader |
|
|
** or one of its parents. First tries to get the resource by calling |
|
|
** <code>getResource()</code> on the parent classloader. |
|
|
** If the parent classloader returns null then it tries finding the |
|
|
** resource by calling <code>findResource()</code> on this |
|
|
** classloader. |
|
|
** <p> |
|
|
** Subclasses should not override this method but should override |
|
|
** <code>findResource()</code> which is called by this method. |
|
|
** |
|
|
** @param name the name of the resource relative to this |
|
|
** classloader. |
|
|
** @return the URL to the resource or null when not found. |
|
|
**/ |
|
|
public URL getResource(String name) { |
|
|
URL result; |
|
|
|
|
|
if (parent == null) |
|
|
// XXX - try bootstrap classloader; |
|
|
// result = VMClassLoader.getResource(name); |
|
|
return ClassLoader.getSystemResource(name); |
|
|
else |
|
|
result = parent.getResource(name); |
|
|
|
|
|
if (result == null) |
|
|
result = findResource(name); |
|
|
|
|
|
return result; |
|
|
} |
|
|
|
|
|
/** Get a resource as stream using this classloader or one of its |
|
|
** parents. First calls <code>getResource()</code> and if that |
|
|
** returns a URL to the resource then it calls and returns the |
|
|
** InputStream given by <code>URL.openStream()</code>. |
|
|
** <p> |
|
|
** Subclasses should not override this method but should override |
|
|
** <code>findResource()</code> which is called by this method. |
|
|
** |
|
|
** @param name the name of the resource relative to this |
|
|
** classloader. |
|
|
** @return An InputStream to the resource or null when the resource |
|
|
** could not be found or when the stream could not be opened. |
|
|
**/ |
|
|
public InputStream getResourceAsStream(String name) { |
|
|
URL url = getResource(name); |
|
|
if (url == null) |
|
|
return(null); |
|
|
|
|
|
try { |
|
|
return url.openStream(); |
|
|
} catch(IOException e) { |
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
/** Helper to define a class using a string of bytes. |
|
|
** @param data the data representing the classfile, in classfile format. |
|
|
** @param offset the offset into the data where the classfile starts. |
|
|
** @param len the length of the classfile data in the array. |
|
|
** @return the class that was defined. |
|
|
** @deprecated use defineClass(String,...) instead. |
|
|
**/ |
|
|
protected final Class defineClass(byte[] data, int offset, int len) throws ClassFormatError { |
|
|
return defineClass(null,data,offset,len); |
|
|
} |
|
|
|
|
|
/** Helper to define a class using a string of bytes without a |
|
|
** ProtectionDomain. |
|
|
** <p> |
|
|
** Subclasses should call this method from their |
|
|
** <code>findClass()</code> implementation. |
|
|
** @param name the name to give the class. null if unknown. |
|
|
** @param data the data representing the classfile, in classfile format. |
|
|
** @param offset the offset into the data where the classfile starts. |
|
|
** @param len the length of the classfile data in the array. |
|
|
** @return the class that was defined. |
|
|
** @exception ClassFormatError if the byte array is not in proper classfile format. |
|
|
**/ |
|
|
protected final Class defineClass(String name, byte[] data, int offset, int len) throws ClassFormatError { |
|
|
// XXX - return defineClass(name,data,offset,len,null); |
|
|
Class retval = VMClassLoader.defineClass(this,name,data,offset,len); |
|
|
loadedClasses.put(retval.getName(),retval); |
|
|
return retval; |
|
|
} |
|
|
|
|
|
/** Helper to define a class using a string of bytes. |
|
|
** <p> |
|
|
** Subclasses should call this method from their |
|
|
** <code>findClass()</code> implementation. |
|
|
** |
|
|
** XXX - not implemented yet. Needs native support. |
|
|
** |
|
|
** @param name the name to give the class. null if unknown. |
|
|
** @param data the data representing the classfile, in classfile format. |
|
|
** @param offset the offset into the data where the classfile starts. |
|
|
** @param len the length of the classfile data in the array. |
|
|
** @param domain the ProtectionDomain to give to the class. |
|
|
** null if unknown (the class will get the default protection domain). |
|
|
** @return the class that was defined. |
|
|
** @exception ClassFormatError if the byte array is not in proper |
|
|
** classfile format. |
|
|
** |
|
|
** @since 1.2 |
|
|
**/ |
|
|
protected final Class defineClass(String name, byte[] data, int offset, |
|
|
int len, ProtectionDomain domain) |
|
|
throws ClassFormatError |
|
|
{ |
|
|
/* |
|
|
XXX - needs native support. |
|
|
Class retval |
|
|
= VMClassLoader.defineClass(this,name,data,offset,len,domain); |
|
|
loadedClasses.put(retval.getName(),retval); |
|
|
return retval; |
|
|
*/ |
|
|
return defineClass(name, data, offset, len); |
|
|
} |
|
|
|
|
|
/** Helper to resolve all references to other classes from this class. |
|
|
** @param c the class to resolve. |
|
|
**/ |
|
|
protected final void resolveClass(Class c) { |
|
|
VMClassLoader.resolveClass(c); |
|
|
} |
|
|
|
|
|
/** Helper to find a Class using the system classloader, |
|
|
** possibly loading it. |
|
|
** @param name the name of the class to find. |
|
|
** @return the found class |
|
|
** @exception ClassNotFoundException if the class cannot be found. |
|
|
**/ |
|
|
protected final Class findSystemClass(String name) throws ClassNotFoundException { |
|
|
return Class.forName(name); |
|
|
} |
|
|
|
|
|
/** Helper to set the signers of a class. |
|
|
** @param c the Class to set signers of |
|
|
** @param signers the signers to set |
|
|
**/ |
|
|
protected final void setSigners(Class c, Object[] signers) { |
|
|
c.setSigners(signers); |
|
|
} |
|
|
|
|
|
/** Helper to find an already-loaded class in this ClassLoader. |
|
|
** @param name the name of the class to find. |
|
|
** @return the found Class, or null if it is not found. |
|
|
**/ |
|
|
protected final Class findLoadedClass(String name) { |
|
|
return (Class)loadedClasses.get(name); |
|
|
} |
|
|
|
|
|
/** Get the URL to a resource using the system classloader. |
|
|
** @param name the name of the resource relative to the |
|
|
** system classloader. |
|
|
** @return the URL to the resource. |
|
|
**/ |
|
|
public static final URL getSystemResource(String name) { |
|
|
if (name.startsWith("/")) |
|
|
name = name.substring(1); |
|
|
String cp = System.getProperty("java.class.path"); |
|
|
if (cp == null) |
|
|
return(null); |
|
|
|
|
|
StringTokenizer st = new StringTokenizer(cp, |
|
|
File.pathSeparator); |
|
|
while(st.hasMoreTokens()) { |
|
|
String path = st.nextToken(); |
|
|
if (path.toLowerCase().endsWith(".zip") || |
|
|
path.toLowerCase().endsWith(".jar")) |
|
|
return(null); // Not implemented yet |
|
|
File f; |
|
|
if (path.endsWith(File.separator)) |
|
|
f = new File(path + name); |
|
|
else |
|
|
f = new File(path + File.separator + name); |
|
|
|
|
|
if (f.exists()) |
|
|
try { |
|
|
return new URL("file://" + |
|
|
f.getAbsolutePath()); |
|
|
} catch(MalformedURLException e) { |
|
|
return null; |
|
|
} |
|
|
} |
|
|
return(null); |
|
|
} |
|
|
|
|
|
/** Get a resource using the system classloader. |
|
|
** @param name the name of the resource relative to the |
|
|
** system classloader. |
|
|
** @return the resource. |
|
|
**/ |
|
|
public static final InputStream getSystemResourceAsStream(String name) { |
|
|
try { |
|
|
URL url = getSystemResource(name); |
|
|
if (url == null) |
|
|
return(null); |
|
|
return url.openStream(); |
|
|
} catch(IOException e) { |
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
/** |
|
|
* Defines a new package and creates a Package object. |
|
|
* The package should be defined before any class in the package is |
|
|
* defined with <code>defineClass()</code>. The package should not yet |
|
|
* be defined before in this classloader or in one of its parents (which |
|
|
* means that <code>getPackage()</code> should return <code>null</code>). |
|
|
* All parameters except the <code>name</code> of the package may be |
|
|
* <code>null</code>. |
|
|
* <p> |
|
|
* Subclasses should call this method from their <code>findClass()</code> |
|
|
* implementation before calling <code>defineClass()</code> on a Class |
|
|
* in a not yet defined Package (which can be checked by calling |
|
|
* <code>getPackage()</code>). |
|
|
* |
|
|
* @param name The name of the Package |
|
|
* @param specTitle The name of the specification |
|
|
* @param specVendor The name of the specification designer |
|
|
* @param specVersion The version of this specification |
|
|
* @param implTitle The name of the implementation |
|
|
* @param implVendor The vendor that wrote this implementation |
|
|
* @param implVersion The version of this implementation |
|
|
* @param sealed If sealed the origin of the package classes |
|
|
* @return the Package object for the specified package |
|
|
* |
|
|
* @exception IllegalArgumentException if the package name is null or if |
|
|
* it was already defined by this classloader or one of its parents. |
|
|
* |
|
|
* @see Package |
|
|
* @since 1.2 |
|
|
*/ |
|
|
protected Package definePackage(String name, |
|
|
String specTitle, String specVendor, String specVersion, |
|
|
String implTitle, String implVendor, String implVersion, |
|
|
URL sealed) { |
|
|
|
|
|
if (getPackage(name) != null) |
|
|
throw new IllegalArgumentException("Package " + name |
|
|
+ " already defined"); |
|
|
Package p = new Package(name, |
|
|
specTitle, specVendor, specVersion, |
|
|
implTitle, implVendor, implVersion, |
|
|
sealed); |
|
|
definedPackages.put(name, p); |
|
|
|
|
|
return p; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Returns the Package object for the requested package name. It returns |
|
|
* null when the package is not defined by this classloader or one of its |
|
|
* parents. |
|
|
* |
|
|
* @since 1.2 |
|
|
*/ |
|
|
protected final Package getPackage(String name) { |
|
|
Package p; |
|
|
if (parent == null) |
|
|
// XXX - Should we use the bootstrap classloader? |
|
|
p = null; |
|
|
else |
|
|
p = parent.getPackage(name); |
|
|
|
|
|
if (p == null) |
|
|
p = (Package)definedPackages.get(name); |
|
|
|
|
|
return p; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Returns all Package objects defined by this classloader and its parents. |
|
|
* |
|
|
* @since 1.2 |
|
|
*/ |
|
|
protected Package[] getPackages() { |
|
|
Package[] allPackages; |
|
|
|
|
|
// Get all our packages. |
|
|
Package[] packages; |
|
|
synchronized(definedPackages) { |
|
|
packages = new Package[definedPackages.size()]; |
|
|
Enumeration e = definedPackages.elements(); |
|
|
int i = 0; |
|
|
while (e.hasMoreElements()) { |
|
|
packages[i] = (Package)e.nextElement(); |
|
|
i++; |
|
|
} |
|
|
} |
|
|
|
|
|
// If we have a parent get all packages defined by our parents. |
|
|
if (parent != null) { |
|
|
Package[] parentPackages = parent.getPackages(); |
|
|
allPackages = new Package[parentPackages.length+packages.length]; |
|
|
System.arraycopy(parentPackages, 0, allPackages, 0, |
|
|
parentPackages.length); |
|
|
System.arraycopy(packages, 0, allPackages, parentPackages.length, |
|
|
packages.length); |
|
|
} else |
|
|
// XXX - Should we use the bootstrap classloader? |
|
|
allPackages = packages; |
|
|
|
|
|
return allPackages; |
|
|
} |
|
259 |
|
|
260 |
/** |
// Can the class be loaded by one of our parent? |
261 |
* Returns the parent of this classloader. |
try |
262 |
* If the parent of this classloader is the bootstrap classloader then |
{ |
263 |
* this method returns <code>null</code>. |
if (parent == null) |
264 |
* |
// XXX - use the bootstrap classloader |
265 |
* @exception SecurityException thrown when the classloader of the calling |
// return VMClassLoader.loadClass(name, resolve); |
266 |
* class is not the bootstrap (null) or the current classloader and the |
return findSystemClass(name); |
267 |
* caller also doesn't have the |
return parent.loadClass(name, resolve); |
|
* <code>RuntimePermission("getClassLoader")</code>. |
|
|
* |
|
|
* @since 1.2 |
|
|
*/ |
|
|
public final ClassLoader getParent() { |
|
|
// Check if we may return the parent classloader |
|
|
SecurityManager sm = System.getSecurityManager(); |
|
|
if (sm != null) { |
|
|
Class c = VMSecurityManager.getClassContext()[1]; |
|
|
ClassLoader cl = c.getClassLoader(); |
|
|
if (cl != null && cl != this) |
|
|
sm.checkPermission(new RuntimePermission("getClassLoader")); |
|
268 |
} |
} |
269 |
return parent; |
catch (ClassNotFoundException e) |
270 |
} |
{ |
271 |
|
// Ignore, use findClass(). |
|
/** |
|
|
* Returns the system classloader. The system classloader (also called |
|
|
* the application classloader) is the classloader that was used to |
|
|
* load the application classes on the classpath (given by the system |
|
|
* property <code>java.class.path</code>. |
|
|
* <p> |
|
|
* Note that this is different from the bootstrap classloader that |
|
|
* actually loads all the real "system" classes (the bootstrap classloader |
|
|
* is the parent of the returned system classloader). |
|
|
* |
|
|
* @exception SecurityException thrown when the classloader of the calling |
|
|
* class is not the bootstrap (null) or system classloader and the caller |
|
|
* also doesn't have the <code>RuntimePermission("getClassLoader")</code>. |
|
|
* |
|
|
* @since 1.2 |
|
|
*/ |
|
|
public static ClassLoader getSystemClassLoader() { |
|
|
// Check if we may return the system classloader |
|
|
SecurityManager sm = System.getSecurityManager(); |
|
|
if (sm != null) { |
|
|
Class c = VMSecurityManager.getClassContext()[1]; |
|
|
ClassLoader cl = c.getClassLoader(); |
|
|
if (cl != null && cl != systemClassLoader) |
|
|
sm.checkPermission(new RuntimePermission("getClassLoader")); |
|
272 |
} |
} |
|
return systemClassLoader; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Called for every class name that is needed but has not yet been |
|
|
* defined by this classloader or one of its parents. It is called by |
|
|
* <code>loadClass()</code> after both <code>findLoadedClass()</code> and |
|
|
* <code>parent.loadClass()</code> couldn't provide the requested class. |
|
|
* <p> |
|
|
* The default implementation throws a <code>ClassNotFoundException</code>. |
|
|
* Subclasses should override this method. An implementation of this |
|
|
* method in a subclass should get the class bytes of the class (if it can |
|
|
* find them), if the package of the requested class doesn't exist it |
|
|
* should define the package and finally it should call define the actual |
|
|
* class. It does not have to resolve the class. It should look something |
|
|
* like the following: |
|
|
* <p> |
|
|
<pre> |
|
|
// Get the bytes that describe the requested class |
|
|
byte[] classBytes = classLoaderSpecificWayToFindClassBytes(name); |
|
|
// Get the package name |
|
|
int lastDot = name.lastIndexOf('.'); |
|
|
if (lastDot != -1) { |
|
|
String packageName = name.substring(0,lastDot); |
|
|
// Look if the package already exists |
|
|
if (getPackage(pkg) == null) { |
|
|
// define the package |
|
|
definePackage(packageName, ...); |
|
|
} |
|
|
// Define and return the class |
|
|
return defineClass(name, classBytes, 0, classBytes.length); |
|
|
</pre> |
|
|
* <p> |
|
|
* <code>loadClass()</code> makes sure that the <code>Class</code> |
|
|
* returned by <code>findClass()</code> will later be returned by |
|
|
* <code>findLoadedClass()</code> when the same class name is |
|
|
* requested. |
|
|
* |
|
|
* @param name class name to find (including the package name) |
|
|
* @return the requested Class |
|
|
* @exception ClassNotFoundException when the class can not be found |
|
|
* |
|
|
* @since 1.2 |
|
|
*/ |
|
|
protected Class findClass(String name) throws ClassNotFoundException { |
|
|
throw new ClassNotFoundException(name); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Called whenever a resource is needed that could not be provided by |
|
|
* one of the parents of this classloader. It is called by |
|
|
* <code>getResource()</code> after <code>parent.getResource()</code> |
|
|
* couldn't provide the requested resource. |
|
|
* <p> |
|
|
* The default implementation always returns null. Subclasses should |
|
|
* override this method when they can provide a way to return a URL |
|
|
* to a named resource. |
|
|
* |
|
|
* @param name the name of the resource to be found. |
|
|
* @return a URL to the named resource or null when not found. |
|
|
* |
|
|
* @since 1.2 |
|
|
*/ |
|
|
protected URL findResource(String name) { |
|
|
return null; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Called whenever all locations of a named resource are needed. |
|
|
* It is called by <code>getResources()</code> after it has called |
|
|
* <code>parent.getResources()</code>. The results are combined by |
|
|
* the <code>getResources()</code> method. |
|
|
* <p> |
|
|
* The default implementation always returns an empty Enumeration. |
|
|
* Subclasses should override it when they can provide an Enumeration of |
|
|
* URLS (possibly just one element) to the named resource. |
|
|
* The first URL of the Enumeration should be the same as the one |
|
|
* returned by <code>findResource</code>. |
|
|
* |
|
|
* @param name the name of the resource to be found. |
|
|
* @return a possibly empty Enumeration of URLs to the named resource. |
|
|
* |
|
|
* @since 1.2 |
|
|
*/ |
|
|
protected Enumeration findResources(String name) throws IOException { |
|
|
return EmptyEnumeration.getInstance(); |
|
|
} |
|
273 |
|
|
274 |
/** |
// Still not found, we have to do it ourself. |
275 |
* Returns an Enumeration of all resources with a given name that can |
c = findClass(name); |
276 |
* be found by this classloader and its parents. Certain classloaders |
if (resolve) |
277 |
* (such as the URLClassLoader when given multiple jar files) can have |
resolveClass(c); |
278 |
* multiple resources with the same name that come from multiple locations. |
return c; |
279 |
* It can also occur that a parent classloader offers a resource with a |
} |
280 |
* certain name and the child classloader also offers a resource with that |
|
281 |
* same name. <code>getResource() only offers the first resource (of the |
/** |
282 |
* parent) with a given name. This method lists all resources with the |
* Called for every class name that is needed but has not yet been |
283 |
* same name. |
* defined by this classloader or one of its parents. It is called by |
284 |
* <p> |
* <code>loadClass()</code> after both <code>findLoadedClass()</code> and |
285 |
* The Enumeration is created by first calling <code>getResources()</code> |
* <code>parent.loadClass()</code> couldn't provide the requested class. |
286 |
* on the parent classloader and then calling <code>findResources()</code> |
* |
287 |
* on this classloader. |
* <p>The default implementation throws a |
288 |
* |
* <code>ClassNotFoundException</code>. Subclasses should override this |
289 |
* @since 1.2 |
* method. An implementation of this method in a subclass should get the |
290 |
*/ |
* class bytes of the class (if it can find them), if the package of the |
291 |
public final Enumeration getResources(String name) throws IOException { |
* requested class doesn't exist it should define the package and finally |
292 |
Enumeration parentResources; |
* it should call define the actual class. It does not have to resolve the |
293 |
if (parent == null) |
* class. It should look something like the following:<br> |
294 |
// XXX - Should use the bootstrap classloader |
* |
295 |
parentResources = EmptyEnumeration.getInstance(); |
* <pre> |
296 |
|
* // Get the bytes that describe the requested class |
297 |
|
* byte[] classBytes = classLoaderSpecificWayToFindClassBytes(name); |
298 |
|
* // Get the package name |
299 |
|
* int lastDot = name.lastIndexOf('.'); |
300 |
|
* if (lastDot != -1) |
301 |
|
* { |
302 |
|
* String packageName = name.substring(0, lastDot); |
303 |
|
* // Look if the package already exists |
304 |
|
* if (getPackage(pkg) == null) |
305 |
|
* { |
306 |
|
* // define the package |
307 |
|
* definePackage(packageName, ...); |
308 |
|
* } |
309 |
|
* } |
310 |
|
* // Define and return the class |
311 |
|
* return defineClass(name, classBytes, 0, classBytes.length); |
312 |
|
* </pre> |
313 |
|
* |
314 |
|
* <p><code>loadClass()</code> makes sure that the <code>Class</code> |
315 |
|
* returned by <code>findClass()</code> will later be returned by |
316 |
|
* <code>findLoadedClass()</code> when the same class name is requested. |
317 |
|
* |
318 |
|
* @param name class name to find (including the package name) |
319 |
|
* @return the requested Class |
320 |
|
* @throws ClassNotFoundException when the class can not be found |
321 |
|
* @since 1.2 |
322 |
|
*/ |
323 |
|
protected Class findClass(String name) throws ClassNotFoundException |
324 |
|
{ |
325 |
|
throw new ClassNotFoundException(name); |
326 |
|
} |
327 |
|
|
328 |
|
/** |
329 |
|
* Helper to define a class using a string of bytes. This version is not |
330 |
|
* secure. |
331 |
|
* |
332 |
|
* @param data the data representing the classfile, in classfile format |
333 |
|
* @param offset the offset into the data where the classfile starts |
334 |
|
* @param len the length of the classfile data in the array |
335 |
|
* @return the class that was defined |
336 |
|
* @throws ClassFormatError if data is not in proper classfile format |
337 |
|
* @throws IndexOutOfBoundsException if offset or len is negative, or |
338 |
|
* offset + len exceeds data |
339 |
|
* @deprecated use {@link #defineClass(String, byte[], int, int)} instead |
340 |
|
*/ |
341 |
|
protected final Class defineClass(byte[] data, int offset, int len) |
342 |
|
throws ClassFormatError |
343 |
|
{ |
344 |
|
return defineClass(null, data, offset, len); |
345 |
|
} |
346 |
|
|
347 |
|
/** |
348 |
|
* Helper to define a class using a string of bytes without a |
349 |
|
* ProtectionDomain. Subclasses should call this method from their |
350 |
|
* <code>findClass()</code> implementation. The name should use '.' |
351 |
|
* separators, and discard the trailing ".class". The default protection |
352 |
|
* domain is <code>Policy.getPolicy().getPermissions(null, null)<code>. |
353 |
|
* |
354 |
|
* @param name the name to give the class, or null if unknown |
355 |
|
* @param data the data representing the classfile, in classfile format |
356 |
|
* @param offset the offset into the data where the classfile starts |
357 |
|
* @param len the length of the classfile data in the array |
358 |
|
* @return the class that was defined |
359 |
|
* @throws ClassFormatError if data is not in proper classfile format |
360 |
|
* @throws IndexOutOfBoundsException if offset or len is negative, or |
361 |
|
* offset + len exceeds data |
362 |
|
* @throws SecurityException if name starts with "java." |
363 |
|
* @since 1.1 |
364 |
|
*/ |
365 |
|
protected final Class defineClass(String name, byte[] data, int offset, |
366 |
|
int len) throws ClassFormatError |
367 |
|
{ |
368 |
|
// XXX - return defineClass(name, data, offset, len, null); |
369 |
|
Class retval = VMClassLoader.defineClass(this, name, data, offset, len); |
370 |
|
loadedClasses.put(retval.getName(), retval); |
371 |
|
return retval; |
372 |
|
} |
373 |
|
|
374 |
|
/** |
375 |
|
* Helper to define a class using a string of bytes. Subclasses should call |
376 |
|
* this method from their <code>findClass()</code> implementation. If the |
377 |
|
* domain is null, the default of |
378 |
|
* <code>Policy.getPolicy().getPermissions(null, null)<code> is used. |
379 |
|
* Once a class has been defined in a package, all further classes in that |
380 |
|
* package must have the same set of certificates or a SecurityException is |
381 |
|
* thrown |
382 |
|
* |
383 |
|
* XXX - not implemented yet. Needs native support. |
384 |
|
* |
385 |
|
* @param name the name to give the class. null if unknown |
386 |
|
* @param data the data representing the classfile, in classfile format |
387 |
|
* @param offset the offset into the data where the classfile starts |
388 |
|
* @param len the length of the classfile data in the array |
389 |
|
* @param domain the ProtectionDomain to give to the class, null for the |
390 |
|
* default protection domain |
391 |
|
* @return the class that was defined |
392 |
|
* @throws ClassFormatError if data is not in proper classfile format |
393 |
|
* @throws IndexOutOfBoundsException if offset or len is negative, or |
394 |
|
* offset + len exceeds data |
395 |
|
* @throws SecurityException if name starts with "java.", or if certificates |
396 |
|
* do not match up |
397 |
|
* @since 1.2 |
398 |
|
*/ |
399 |
|
protected final Class defineClass(String name, byte[] data, int offset, |
400 |
|
int len, ProtectionDomain domain) |
401 |
|
throws ClassFormatError |
402 |
|
{ |
403 |
|
/* XXX - needs native support. |
404 |
|
Class retval |
405 |
|
= VMClassLoader.defineClass(this, name, data, offset, len, domain); |
406 |
|
loadedClasses.put(retval.getName(), retval); |
407 |
|
return retval; |
408 |
|
*/ |
409 |
|
return defineClass(name, data, offset, len); |
410 |
|
} |
411 |
|
|
412 |
|
/** |
413 |
|
* Links the class, if that has not already been done. Linking basically |
414 |
|
* resolves all references to other classes made by this class. |
415 |
|
* |
416 |
|
* @param c the class to resolve |
417 |
|
* @throws NullPointerException if c is null |
418 |
|
* @throws LinkageError if linking fails |
419 |
|
*/ |
420 |
|
protected final void resolveClass(Class c) |
421 |
|
{ |
422 |
|
VMClassLoader.resolveClass(c); |
423 |
|
} |
424 |
|
|
425 |
|
/** |
426 |
|
* Helper to find a Class using the system classloader, possibly loading it. |
427 |
|
* A subclass usually does not need to call this, if it correctly |
428 |
|
* overrides <code>findClass(String)</code>. |
429 |
|
* |
430 |
|
* @param name the name of the class to find |
431 |
|
* @return the found class |
432 |
|
* @throws ClassNotFoundException if the class cannot be found |
433 |
|
*/ |
434 |
|
protected final Class findSystemClass(String name) |
435 |
|
throws ClassNotFoundException |
436 |
|
{ |
437 |
|
// XXX This should be: |
438 |
|
// return Class.forName(name, false, getSystemClassLoader()); |
439 |
|
return Class.forName(name); |
440 |
|
} |
441 |
|
|
442 |
|
/** |
443 |
|
* Returns the parent of this classloader. If the parent of this |
444 |
|
* classloader is the bootstrap classloader then this method returns |
445 |
|
* <code>null</code>. A security check may be performed on |
446 |
|
* <code>RuntimePermission("getClassLoader")</code>. |
447 |
|
* |
448 |
|
* @throws SecurityException if the security check fails |
449 |
|
* @since 1.2 |
450 |
|
*/ |
451 |
|
public final ClassLoader getParent() |
452 |
|
{ |
453 |
|
// Check if we may return the parent classloader |
454 |
|
SecurityManager sm = System.getSecurityManager(); |
455 |
|
if (sm != null) |
456 |
|
{ |
457 |
|
Class c = VMSecurityManager.getClassContext()[1]; |
458 |
|
ClassLoader cl = c.getClassLoader(); |
459 |
|
if (cl != null && cl != this) |
460 |
|
sm.checkPermission(new RuntimePermission("getClassLoader")); |
461 |
|
} |
462 |
|
return parent; |
463 |
|
} |
464 |
|
|
465 |
|
/** |
466 |
|
* Helper to set the signers of a class. This should be called after |
467 |
|
* defining the class. |
468 |
|
* |
469 |
|
* @param c the Class to set signers of |
470 |
|
* @param signers the signers to set |
471 |
|
* @since 1.1 |
472 |
|
*/ |
473 |
|
protected final void setSigners(Class c, Object[] signers) |
474 |
|
{ |
475 |
|
c.setSigners(signers); |
476 |
|
} |
477 |
|
|
478 |
|
/** |
479 |
|
* Helper to find an already-loaded class in this ClassLoader. |
480 |
|
* |
481 |
|
* @param name the name of the class to find |
482 |
|
* @return the found Class, or null if it is not found |
483 |
|
* @since 1.1 |
484 |
|
*/ |
485 |
|
protected final Class findLoadedClass(String name) |
486 |
|
{ |
487 |
|
return (Class) loadedClasses.get(name); |
488 |
|
} |
489 |
|
|
490 |
|
/** |
491 |
|
* Get the URL to a resource using this classloader or one of its parents. |
492 |
|
* First tries to get the resource by calling <code>getResource()</code> |
493 |
|
* on the parent classloader. If the parent classloader returns null then |
494 |
|
* it tries finding the resource by calling <code>findResource()</code> on |
495 |
|
* this classloader. The resource name should be separated by '/' for path |
496 |
|
* elements. |
497 |
|
* |
498 |
|
* <p>Subclasses should not override this method but should override |
499 |
|
* <code>findResource()</code> which is called by this method. |
500 |
|
* |
501 |
|
* @param name the name of the resource relative to this classloader |
502 |
|
* @return the URL to the resource or null when not found |
503 |
|
*/ |
504 |
|
public URL getResource(String name) |
505 |
|
{ |
506 |
|
URL result; |
507 |
|
|
508 |
|
if (parent == null) |
509 |
|
// XXX - try bootstrap classloader; |
510 |
|
// result = VMClassLoader.getResource(name); |
511 |
|
return ClassLoader.getSystemResource(name); |
512 |
|
result = parent.getResource(name); |
513 |
|
|
514 |
|
if (result == null) |
515 |
|
result = findResource(name); |
516 |
|
return result; |
517 |
|
} |
518 |
|
|
519 |
|
/** |
520 |
|
* Returns an Enumeration of all resources with a given name that can |
521 |
|
* be found by this classloader and its parents. Certain classloaders |
522 |
|
* (such as the URLClassLoader when given multiple jar files) can have |
523 |
|
* multiple resources with the same name that come from multiple locations. |
524 |
|
* It can also occur that a parent classloader offers a resource with a |
525 |
|
* certain name and the child classloader also offers a resource with that |
526 |
|
* same name. <code>getResource() only offers the first resource (of the |
527 |
|
* parent) with a given name. This method lists all resources with the |
528 |
|
* same name. The name should use '/' as path separators. |
529 |
|
* |
530 |
|
* <p>The Enumeration is created by first calling <code>getResources()</code> |
531 |
|
* on the parent classloader and then calling <code>findResources()</code> |
532 |
|
* on this classloader. |
533 |
|
* |
534 |
|
* @param name the resource name |
535 |
|
* @return an enumaration of all resources found |
536 |
|
* @throws IOException if I/O errors occur in the process |
537 |
|
* @since 1.2 |
538 |
|
*/ |
539 |
|
public final Enumeration getResources(String name) throws IOException |
540 |
|
{ |
541 |
|
Enumeration parentResources; |
542 |
|
if (parent == null) |
543 |
|
// XXX - Should use the bootstrap classloader |
544 |
|
parentResources = EmptyEnumeration.getInstance(); |
545 |
|
else |
546 |
|
parentResources = parent.getResources(name); |
547 |
|
return new DoubleEnumeration(parentResources, findResources(name)); |
548 |
|
} |
549 |
|
|
550 |
|
/** |
551 |
|
* Called whenever all locations of a named resource are needed. |
552 |
|
* It is called by <code>getResources()</code> after it has called |
553 |
|
* <code>parent.getResources()</code>. The results are combined by |
554 |
|
* the <code>getResources()</code> method. |
555 |
|
* |
556 |
|
* <p>The default implementation always returns an empty Enumeration. |
557 |
|
* Subclasses should override it when they can provide an Enumeration of |
558 |
|
* URLs (possibly just one element) to the named resource. |
559 |
|
* The first URL of the Enumeration should be the same as the one |
560 |
|
* returned by <code>findResource</code>. |
561 |
|
* |
562 |
|
* @param name the name of the resource to be found |
563 |
|
* @return a possibly empty Enumeration of URLs to the named resource |
564 |
|
* @throws IOException if I/O errors occur in the process |
565 |
|
* @since 1.2 |
566 |
|
*/ |
567 |
|
protected Enumeration findResources(String name) throws IOException |
568 |
|
{ |
569 |
|
return EmptyEnumeration.getInstance(); |
570 |
|
} |
571 |
|
|
572 |
|
/** |
573 |
|
* Called whenever a resource is needed that could not be provided by |
574 |
|
* one of the parents of this classloader. It is called by |
575 |
|
* <code>getResource()</code> after <code>parent.getResource()</code> |
576 |
|
* couldn't provide the requested resource. |
577 |
|
* |
578 |
|
* <p>The default implementation always returns null. Subclasses should |
579 |
|
* override this method when they can provide a way to return a URL |
580 |
|
* to a named resource. |
581 |
|
* |
582 |
|
* @param name the name of the resource to be found |
583 |
|
* @return a URL to the named resource or null when not found |
584 |
|
* @since 1.2 |
585 |
|
*/ |
586 |
|
protected URL findResource(String name) |
587 |
|
{ |
588 |
|
return null; |
589 |
|
} |
590 |
|
|
591 |
|
/** |
592 |
|
* Get the URL to a resource using the system classloader. |
593 |
|
* |
594 |
|
* @param name the name of the resource relative to the system classloader |
595 |
|
* @return the URL to the resource |
596 |
|
* @since 1.1 |
597 |
|
*/ |
598 |
|
public static final URL getSystemResource(String name) |
599 |
|
{ |
600 |
|
//XXX This should be: |
601 |
|
// return getSystemClassLoader().getResource(name); |
602 |
|
if (name.startsWith("/")) |
603 |
|
name = name.substring(1); |
604 |
|
String cp = System.getProperty("java.class.path"); |
605 |
|
if (cp == null) |
606 |
|
return null; |
607 |
|
|
608 |
|
StringTokenizer st = new StringTokenizer(cp, File.pathSeparator); |
609 |
|
while (st.hasMoreTokens()) |
610 |
|
{ |
611 |
|
String path = st.nextToken(); |
612 |
|
if (path.toLowerCase().endsWith(".zip") || |
613 |
|
path.toLowerCase().endsWith(".jar")) |
614 |
|
return null; // Not implemented yet |
615 |
|
File f; |
616 |
|
if (path.endsWith(File.separator)) |
617 |
|
f = new File(path + name); |
618 |
else |
else |
619 |
parentResources = parent.getResources(name); |
f = new File(path + File.separator + name); |
620 |
|
|
621 |
return new DoubleEnumeration(parentResources, findResources(name)); |
if (f.exists()) |
622 |
} |
try |
623 |
|
{ |
624 |
/** |
return new URL("file://" + f.getAbsolutePath()); |
625 |
* Called by <code>Runtime.loadLibrary()</code> to get an absolute path |
} |
626 |
* to a (system specific) library that was requested by a class loaded |
catch (MalformedURLException e) |
627 |
* by this classloader. The default implementation returns |
{ |
628 |
* <code>null</code>. It should be implemented by subclasses when they |
return null; |
629 |
* have a way to find the absolute path to a library. If this method |
} |
630 |
* returns null the library is searched for in the default locations |
} |
631 |
* (the directories listed in the <code>java.library.path</code> system |
return null; |
632 |
* property). |
} |
633 |
* |
|
634 |
* @param name the (system specific) name of the requested library. |
/** |
635 |
* @return the full pathname to the requested library |
* Get an Enumeration of URLs to resources with a given name using the |
636 |
* or null when not found |
* the system classloader. The enumeration firsts lists the resources with |
637 |
* |
* the given name that can be found by the bootstrap classloader followed |
638 |
* @see Runtime#loadLibrary() |
* by the resources with the given name that can be found on the classpath. |
639 |
* @since 1.2 |
* |
640 |
*/ |
* @param name the name of the resource relative to the system classloader |
641 |
protected String findLibrary(String name) |
* @return an Enumeration of URLs to the resources |
642 |
{ |
* @throws IOException if I/O errors occur in the process |
643 |
|
* @since 1.2 |
644 |
|
*/ |
645 |
|
public static Enumeration getSystemResources(String name) throws IOException |
646 |
|
{ |
647 |
|
// XXX should be |
648 |
|
// return getSystemClassLoader().getResources(name); |
649 |
|
return systemClassLoader.getResources(name); |
650 |
|
} |
651 |
|
|
652 |
|
/** |
653 |
|
* Get a resource as stream using this classloader or one of its parents. |
654 |
|
* First calls <code>getResource()</code> and if that returns a URL to |
655 |
|
* the resource then it calls and returns the InputStream given by |
656 |
|
* <code>URL.openStream()</code>. |
657 |
|
* |
658 |
|
* <p>Subclasses should not override this method but should override |
659 |
|
* <code>findResource()</code> which is called by this method. |
660 |
|
* |
661 |
|
* @param name the name of the resource relative to this classloader |
662 |
|
* @return an InputStream to the resource, or null |
663 |
|
* @since 1.1 |
664 |
|
*/ |
665 |
|
public InputStream getResourceAsStream(String name) |
666 |
|
{ |
667 |
|
URL url = getResource(name); |
668 |
|
if (url == null) |
669 |
|
return null; |
670 |
|
try |
671 |
|
{ |
672 |
|
return url.openStream(); |
673 |
|
} |
674 |
|
catch(IOException e) |
675 |
|
{ |
676 |
return null; |
return null; |
677 |
} |
} |
678 |
|
} |
679 |
|
|
680 |
/** Get an Enumeration of URLs to resources with a given name using |
/** |
681 |
** the system classloader. The enumeration firsts lists the resources |
* Get a resource using the system classloader. |
682 |
** with the given name that can be found by the bootstrap classloader |
* |
683 |
** followed by the resources with the given name that can be found |
* @param name the name of the resource relative to the system classloader |
684 |
** on the classpath. |
* @return an input stream for the resource, or null |
685 |
** @param name the name of the resource relative to the |
* @since 1.1 |
686 |
** system classloader. |
*/ |
687 |
** @return an Enumeration of URLs to the resources. |
public static final InputStream getSystemResourceAsStream(String name) |
688 |
** |
{ |
689 |
** @since 1.2 |
try |
690 |
**/ |
{ |
691 |
public static Enumeration getSystemResources(String name) |
URL url = getSystemResource(name); |
692 |
throws IOException |
if (url == null) |
693 |
{ |
return null; |
694 |
return systemClassLoader.getResources(name); |
return url.openStream(); |
695 |
} |
} |
696 |
|
catch(IOException e) |
697 |
|
{ |
698 |
|
return null; |
699 |
|
} |
700 |
|
} |
701 |
|
|
702 |
|
/** |
703 |
|
* Returns the system classloader. The system classloader (also called |
704 |
|
* the application classloader) is the classloader that was used to |
705 |
|
* load the application classes on the classpath (given by the system |
706 |
|
* property <code>java.class.path</code>. This is set as the context |
707 |
|
* class loader for a thread. The system property |
708 |
|
* <code>java.system.class.loader</code>, if defined, is taken to be the |
709 |
|
* name of the class to use as the system class loader, otherwise this |
710 |
|
* uses gnu.java.lang.SystemClassLoader. |
711 |
|
* |
712 |
|
* <p>Note that this is different from the bootstrap classloader that |
713 |
|
* actually loads all the real "system" classes (the bootstrap classloader |
714 |
|
* is the parent of the returned system classloader). |
715 |
|
* |
716 |
|
* <p>A security check will be performed for |
717 |
|
* <code>RuntimePermission("getClassLoader")</code> if the calling class |
718 |
|
* is not a parent of the system class loader. |
719 |
|
* |
720 |
|
* @return the system class loader |
721 |
|
* @throws SecurityException if the security check fails |
722 |
|
* @throws IllegalStateException if this is called recursively |
723 |
|
* @throws Error if <code>java.system.class.loader</code> fails to load |
724 |
|
* @since 1.2 |
725 |
|
*/ |
726 |
|
public static ClassLoader getSystemClassLoader() |
727 |
|
{ |
728 |
|
//XXX This needs to check for java.system.class.loader. |
729 |
|
// Check if we may return the system classloader |
730 |
|
SecurityManager sm = System.getSecurityManager(); |
731 |
|
if (sm != null) |
732 |
|
{ |
733 |
|
Class c = VMSecurityManager.getClassContext()[1]; |
734 |
|
ClassLoader cl = c.getClassLoader(); |
735 |
|
if (cl != null && cl != systemClassLoader) |
736 |
|
sm.checkPermission(new RuntimePermission("getClassLoader")); |
737 |
|
} |
738 |
|
return systemClassLoader; |
739 |
|
} |
740 |
|
|
741 |
|
/** |
742 |
|
* Defines a new package and creates a Package object. The package should |
743 |
|
* be defined before any class in the package is defined with |
744 |
|
* <code>defineClass()</code>. The package should not yet be defined |
745 |
|
* before in this classloader or in one of its parents (which means that |
746 |
|
* <code>getPackage()</code> should return <code>null</code>). All |
747 |
|
* parameters except the <code>name</code> of the package may be |
748 |
|
* <code>null</code>. |
749 |
|
* |
750 |
|
* <p>Subclasses should call this method from their <code>findClass()</code> |
751 |
|
* implementation before calling <code>defineClass()</code> on a Class |
752 |
|
* in a not yet defined Package (which can be checked by calling |
753 |
|
* <code>getPackage()</code>). |
754 |
|
* |
755 |
|
* @param name the name of the Package |
756 |
|
* @param specTitle the name of the specification |
757 |
|
* @param specVendor the name of the specification designer |
758 |
|
* @param specVersion the version of this specification |
759 |
|
* @param implTitle the name of the implementation |
760 |
|
* @param implVendor the vendor that wrote this implementation |
761 |
|
* @param implVersion the version of this implementation |
762 |
|
* @param sealed if sealed the origin of the package classes |
763 |
|
* @return the Package object for the specified package |
764 |
|
* @throws IllegalArgumentException if the package name is null or it |
765 |
|
* was already defined by this classloader or one of its parents |
766 |
|
* @see Package |
767 |
|
* @since 1.2 |
768 |
|
*/ |
769 |
|
protected Package definePackage(String name, String specTitle, |
770 |
|
String specVendor, String specVersion, |
771 |
|
String implTitle, String implVendor, |
772 |
|
String implVersion, URL sealed) |
773 |
|
{ |
774 |
|
if (getPackage(name) != null) |
775 |
|
throw new IllegalArgumentException("Package " + name |
776 |
|
+ " already defined"); |
777 |
|
Package p = new Package(name, specTitle, specVendor, specVersion, |
778 |
|
implTitle, implVendor, implVersion, sealed); |
779 |
|
definedPackages.put(name, p); |
780 |
|
return p; |
781 |
|
} |
782 |
|
|
783 |
|
/** |
784 |
|
* Returns the Package object for the requested package name. It returns |
785 |
|
* null when the package is not defined by this classloader or one of its |
786 |
|
* parents. |
787 |
|
* |
788 |
|
* @param name the package name to find |
789 |
|
* @return the package, if defined |
790 |
|
* @since 1.2 |
791 |
|
*/ |
792 |
|
protected final Package getPackage(String name) |
793 |
|
{ |
794 |
|
Package p; |
795 |
|
if (parent == null) |
796 |
|
// XXX - Should we use the bootstrap classloader? |
797 |
|
p = null; |
798 |
|
else |
799 |
|
p = parent.getPackage(name); |
800 |
|
|
801 |
|
if (p == null) |
802 |
|
p = (Package)definedPackages.get(name); |
803 |
|
return p; |
804 |
|
} |
805 |
|
|
806 |
|
/** |
807 |
|
* Returns all Package objects defined by this classloader and its parents. |
808 |
|
* |
809 |
|
* @return an array of all defined packages |
810 |
|
* @since 1.2 |
811 |
|
*/ |
812 |
|
protected Package[] getPackages() |
813 |
|
{ |
814 |
|
Package[] allPackages; |
815 |
|
|
816 |
|
// Get all our packages. |
817 |
|
Package[] packages; |
818 |
|
synchronized(definedPackages) |
819 |
|
{ |
820 |
|
packages = new Package[definedPackages.size()]; |
821 |
|
Enumeration e = definedPackages.elements(); |
822 |
|
int i = 0; |
823 |
|
while (e.hasMoreElements()) |
824 |
|
{ |
825 |
|
packages[i] = (Package)e.nextElement(); |
826 |
|
i++; |
827 |
|
} |
828 |
|
} |
829 |
|
|
830 |
|
// If we have a parent get all packages defined by our parents. |
831 |
|
if (parent != null) |
832 |
|
{ |
833 |
|
Package[] parentPackages = parent.getPackages(); |
834 |
|
allPackages = new Package[parentPackages.length + packages.length]; |
835 |
|
System.arraycopy(parentPackages, 0, allPackages, 0, |
836 |
|
parentPackages.length); |
837 |
|
System.arraycopy(packages, 0, allPackages, parentPackages.length, |
838 |
|
packages.length); |
839 |
|
} else |
840 |
|
// XXX - Should we use the bootstrap classloader? |
841 |
|
allPackages = packages; |
842 |
|
|
843 |
|
return allPackages; |
844 |
|
} |
845 |
|
|
846 |
|
/** |
847 |
|
* Called by <code>Runtime.loadLibrary()</code> to get an absolute path |
848 |
|
* to a (system specific) library that was requested by a class loaded |
849 |
|
* by this classloader. The default implementation returns |
850 |
|
* <code>null</code>. It should be implemented by subclasses when they |
851 |
|
* have a way to find the absolute path to a library. If this method |
852 |
|
* returns null the library is searched for in the default locations |
853 |
|
* (the directories listed in the <code>java.library.path</code> system |
854 |
|
* property). |
855 |
|
* |
856 |
|
* @param name the (system specific) name of the requested library |
857 |
|
* @return the full pathname to the requested library, or null |
858 |
|
* @see Runtime#loadLibrary() |
859 |
|
* @since 1.2 |
860 |
|
*/ |
861 |
|
protected String findLibrary(String name) |
862 |
|
{ |
863 |
|
return null; |
864 |
|
} |
865 |
|
|
866 |
|
/** |
867 |
|
* Set the default assertion status for classes loaded by this classloader, |
868 |
|
* used unless overridden by a package or class request. |
869 |
|
* |
870 |
|
* @param enabled true to set the default to enabled |
871 |
|
* @see #setClassAssertionStatus(String, boolean) |
872 |
|
* @see #setPackageAssertionStatus(String, boolean) |
873 |
|
* @see #clearAssertionStatus() |
874 |
|
* @since 1.4 |
875 |
|
* @XXX Implement for 1.4 compatibility. |
876 |
|
public void setDefaultAssertionStatus(boolean enabled) |
877 |
|
{ |
878 |
|
defaultAssertionStatus = enabled; |
879 |
|
} |
880 |
|
*/ |
881 |
|
|
882 |
|
/** |
883 |
|
* Set the default assertion status for packages, used unless overridden |
884 |
|
* by a class request. This default also covers subpackages, unless they |
885 |
|
* are also specified. The unnamed package should use null for the name. |
886 |
|
* |
887 |
|
* @param name the package (and subpackages) to affect |
888 |
|
* @param enabled true to set the default to enabled |
889 |
|
* @see #setDefaultAssertionStatus(String, boolean) |
890 |
|
* @see #setClassAssertionStatus(String, boolean) |
891 |
|
* @see #clearAssertionStatus() |
892 |
|
* @since 1.4 |
893 |
|
* @XXX Implement for 1.4 compatibility. |
894 |
|
public synchronized void setPackageAssertionStatus(String name, |
895 |
|
boolean enabled) |
896 |
|
{ |
897 |
|
if (packageAssertionStatus == null) |
898 |
|
packageAssertionStatus |
899 |
|
= new HashMap(systemPackageAssertionStatus); |
900 |
|
packageAssertionStatus.put(name, Boolean.valueOf(enabled)); |
901 |
|
} |
902 |
|
*/ |
903 |
|
|
904 |
|
/** |
905 |
|
* Set the default assertion status for a class. This only affects the |
906 |
|
* status of top-level classes, any other string is harmless. |
907 |
|
* |
908 |
|
* @param name the class to affect |
909 |
|
* @param enabled true to set the default to enabled |
910 |
|
* @throws NullPointerException if name is null |
911 |
|
* @see #setDefaultAssertionStatus(String, boolean) |
912 |
|
* @see #setPackageAssertionStatus(String, boolean) |
913 |
|
* @see #clearAssertionStatus() |
914 |
|
* @since 1.4 |
915 |
|
* @XXX Implement for 1.4 compatibility. |
916 |
|
public synchronized void setClassAssertionStatus(String name, |
917 |
|
boolean enabled) |
918 |
|
{ |
919 |
|
if (classAssertionStatus == null) |
920 |
|
classAssertionStatus = new HashMap(systemClassAssertionStatus); |
921 |
|
// The toString() hack catches null, as required. |
922 |
|
classAssertionStatus.put(name.toString(), Boolean.valueOf(enabled)); |
923 |
|
} |
924 |
|
*/ |
925 |
|
|
926 |
|
/** |
927 |
|
* Resets the default assertion status of this classloader, its packages |
928 |
|
* and classes, all to false. This allows overriding defaults inherited |
929 |
|
* from the command line. |
930 |
|
* |
931 |
|
* @see #setDefaultAssertionStatus(boolean) |
932 |
|
* @see #setClassAssertionStatus(String, boolean) |
933 |
|
* @see #setPackageAssertionStatus(String, boolean) |
934 |
|
* @since 1.4 |
935 |
|
* @XXX Implement for 1.4 compatibility. |
936 |
|
public synchronized void clearAssertionStatus() |
937 |
|
{ |
938 |
|
defaultAssertionStatus = false; |
939 |
|
packageAssertionStatus = new HashMap(); |
940 |
|
classAssertionStatus = new HashMap(); |
941 |
|
} |
942 |
|
*/ |
943 |
|
|
944 |
} |
} |
945 |
|
|