1 /* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
42 import java.io.ByteArrayOutputStream;
43 import java.io.EOFException;
45 import java.io.FileInputStream;
46 import java.io.FilePermission;
47 import java.io.IOException;
48 import java.io.InputStream;
49 import java.security.AccessControlContext;
50 import java.security.AccessController;
51 import java.security.CodeSource;
52 import java.security.PermissionCollection;
53 import java.security.PrivilegedAction;
54 import java.security.SecureClassLoader;
55 import java.security.cert.Certificate;
56 import java.util.Enumeration;
57 import java.util.HashMap;
58 import java.util.Iterator;
59 import java.util.StringTokenizer;
60 import java.util.Vector;
61 import java.util.jar.Attributes;
62 import java.util.jar.JarEntry;
63 import java.util.jar.JarFile;
64 import java.util.jar.Manifest;
65 import gnu.gcj.runtime.SharedLibHelper;
67 import gnu.java.net.protocol.core.CoreInputStream;
70 * A secure class loader that can load classes and resources from
71 * multiple locations. Given an array of <code>URL</code>s this class
72 * loader will retrieve classes and resources by fetching them from
73 * possible remote locations. Each <code>URL</code> is searched in
74 * order in which it was added. If the file portion of the
75 * <code>URL</code> ends with a '/' character then it is interpreted
76 * as a base directory, otherwise it is interpreted as a jar file from
77 * which the classes/resources are resolved.
79 * <p>New instances can be created by two static
80 * <code>newInstance()</code> methods or by three public
81 * contructors. Both ways give the option to supply an initial array
82 * of <code>URL</code>s and (optionally) a parent classloader (that is
83 * different from the standard system class loader).</p>
85 * <p>Normally creating a <code>URLClassLoader</code> throws a
86 * <code>SecurityException</code> if a <code>SecurityManager</code> is
87 * installed and the <code>checkCreateClassLoader()</code> method does
88 * not return true. But the <code>newInstance()</code> methods may be
89 * used by any code as long as it has permission to acces the given
90 * <code>URL</code>s. <code>URLClassLoaders</code> created by the
91 * <code>newInstance()</code> methods also explicitly call the
92 * <code>checkPackageAccess()</code> method of
93 * <code>SecurityManager</code> if one is installed before trying to
94 * load a class. Note that only subclasses of
95 * <code>URLClassLoader</code> can add new URLs after the
96 * URLClassLoader had been created. But it is always possible to get
97 * an array of all URLs that the class loader uses to resolve classes
98 * and resources by way of the <code>getURLs()</code> method.</p>
103 * <li>Should the URLClassLoader actually add the locations found in
104 * the manifest or is this the responsibility of some other
105 * loader/(sub)class? (see <a
106 * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html">
107 * Extension Mechanism Architecture - Bundles Extensions</a>)</li>
109 * <li>How does <code>definePackage()</code> and sealing work
112 * <li>We save and use the security context (when a created by
113 * <code>newInstance()</code> but do we have to use it in more
116 * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li>
123 * @author Mark Wielaard (mark@klomp.org)
124 * @author Wu Gansha (gansha.wu@intel.com)
126 public class URLClassLoader extends SecureClassLoader
131 * A global cache to store mappings between URLLoader and URL,
132 * so we can avoid do all the homework each time the same URL
134 * XXX - Keeps these loaders forever which prevents garbage collection.
136 private static HashMap urlloaders = new HashMap();
139 * A cache to store mappings between handler factory and its
140 * private protocol handler cache (also a HashMap), so we can avoid
141 * create handlers each time the same protocol comes.
143 private static HashMap factoryCache = new HashMap(5);
145 // Instance variables
147 /** Locations to load classes from */
148 private final Vector urls = new Vector();
151 * Store pre-parsed information for each url into this vector: each
152 * element is a URL loader. A jar file has its own class-path
153 * attribute which adds to the URLs that will be searched, but this
154 * does not add to the list of urls.
156 private final Vector urlinfos = new Vector();
158 /** Factory used to get the protocol handlers of the URLs */
159 private final URLStreamHandlerFactory factory;
162 * The security context when created from <code>newInstance()</code>
163 * or null when created through a normal constructor or when no
164 * <code>SecurityManager</code> was installed.
166 private final AccessControlContext securityContext;
171 * A <code>URLLoader</code> contains all logic to load resources from a
172 * given base <code>URL</code>.
174 abstract static class URLLoader
177 * Our classloader to get info from if needed.
179 final URLClassLoader classloader;
182 * The base URL from which all resources are loaded.
187 * A <code>CodeSource</code> without any associated certificates.
188 * It is common for classes to not have certificates associated
189 * with them. If they come from the same <code>URLLoader</code>
190 * then it is safe to share the associated <code>CodeSource</code>
191 * between them since <code>CodeSource</code> is immutable.
193 final CodeSource noCertCodeSource;
195 URLLoader(URLClassLoader classloader, URL baseURL)
197 this(classloader, baseURL, baseURL);
200 URLLoader(URLClassLoader classloader, URL baseURL, URL overrideURL)
202 this.classloader = classloader;
203 this.baseURL = baseURL;
204 this.noCertCodeSource = new CodeSource(overrideURL, null);
208 * Returns a <code>Class</code> loaded by this
209 * <code>URLLoader</code>, or <code>null</code> when this loader
210 * either can't load the class or doesn't know how to load classes
213 Class getClass(String className)
219 * Returns a <code>Resource</code> loaded by this
220 * <code>URLLoader</code>, or <code>null</code> when no
221 * <code>Resource</code> with the given name exists.
223 abstract Resource getResource(String s);
226 * Returns the <code>Manifest</code> associated with the
227 * <code>Resource</code>s loaded by this <code>URLLoader</code> or
228 * <code>null</code> there is no such <code>Manifest</code>.
230 Manifest getManifest()
235 Vector getClassPath()
242 * A <code>Resource</code> represents a resource in some
243 * <code>URLLoader</code>. It also contains all information (e.g.,
244 * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and
245 * <code>InputStream</code>) that is necessary for loading resources
246 * and creating classes from a <code>URL</code>.
248 abstract static class Resource
250 final URLLoader loader;
253 Resource(URLLoader loader, String name)
255 this.loader = loader;
260 * Returns the non-null <code>CodeSource</code> associated with
263 CodeSource getCodeSource()
265 Certificate[] certs = getCertificates();
267 return loader.noCertCodeSource;
269 return new CodeSource(loader.baseURL, certs);
273 * Returns <code>Certificates</code> associated with this
274 * resource, or null when there are none.
276 Certificate[] getCertificates()
282 * Return a <code>URL</code> that can be used to access this resource.
284 abstract URL getURL();
287 * Returns the size of this <code>Resource</code> in bytes or
288 * <code>-1</code> when unknown.
290 abstract int getLength();
293 * Returns the non-null <code>InputStream</code> through which
294 * this resource can be loaded.
296 abstract InputStream getInputStream() throws IOException;
300 * A <code>JarURLLoader</code> is a type of <code>URLLoader</code>
301 * only loading from jar url.
303 static final class JarURLLoader extends URLLoader
305 final JarFile jarfile; // The jar file for this url
306 final URL baseJarURL; // Base jar: url for all resources loaded from jar
308 Vector classPath; // The "Class-Path" attribute of this Jar's manifest
310 public JarURLLoader(URLClassLoader classloader, URL baseURL)
312 super(classloader, baseURL);
314 // Cache url prefix for all resources in this jar url.
315 String external = baseURL.toExternalForm();
316 StringBuffer sb = new StringBuffer(external.length() + 6);
320 String jarURL = sb.toString();
322 this.classPath = null;
323 URL baseJarURL = null;
324 JarFile jarfile = null;
328 new URL(null, jarURL, classloader.getURLStreamHandler("jar"));
331 ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
334 Attributes attributes;
335 String classPathString;
337 if ((manifest = jarfile.getManifest()) != null
338 && (attributes = manifest.getMainAttributes()) != null
340 = attributes.getValue(Attributes.Name.CLASS_PATH))
343 this.classPath = new Vector();
345 StringTokenizer st = new StringTokenizer(classPathString, " ");
346 while (st.hasMoreElements ())
348 String e = st.nextToken ();
351 URL url = new URL(baseURL, e);
352 this.classPath.add(url);
354 catch (java.net.MalformedURLException xx)
361 catch (IOException ioe)
366 this.baseJarURL = baseJarURL;
367 this.jarfile = jarfile;
370 /** get resource with the name "name" in the jar url */
371 Resource getResource(String name)
376 if (name.startsWith("/"))
377 name = name.substring(1);
379 JarEntry je = jarfile.getJarEntry(name);
381 return new JarURLResource(this, name, je);
386 Manifest getManifest()
390 return (jarfile == null) ? null : jarfile.getManifest();
392 catch (IOException ioe)
398 Vector getClassPath()
404 static final class JarURLResource extends Resource
406 private final JarEntry entry;
408 JarURLResource(JarURLLoader loader, String name, JarEntry entry)
414 InputStream getInputStream() throws IOException
416 return ((JarURLLoader) loader).jarfile.getInputStream(entry);
421 return (int) entry.getSize();
424 Certificate[] getCertificates()
426 // We have to get the entry from the jar file again, because the
427 // certificates will not be available until the entire entry has
429 return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name))
437 return new URL(((JarURLLoader) loader).baseJarURL, name,
438 loader.classloader.getURLStreamHandler("jar"));
440 catch (MalformedURLException e)
442 InternalError ie = new InternalError();
450 * Loader for remote directories.
452 static final class RemoteURLLoader extends URLLoader
454 private final String protocol;
456 RemoteURLLoader(URLClassLoader classloader, URL url)
458 super(classloader, url);
459 protocol = url.getProtocol();
463 * Get a remote resource.
464 * Returns null if no such resource exists.
466 Resource getResource(String name)
471 new URL(baseURL, name, classloader.getURLStreamHandler(protocol));
472 URLConnection connection = url.openConnection();
474 // Open the connection and check the stream
475 // just to be sure it exists.
476 int length = connection.getContentLength();
477 InputStream stream = connection.getInputStream();
479 // We can do some extra checking if it is a http request
480 if (connection instanceof HttpURLConnection)
483 ((HttpURLConnection) connection).getResponseCode();
484 if (response / 100 != 2)
489 return new RemoteResource(this, name, url, stream, length);
493 catch (IOException ioe)
501 * A resource from some remote location.
503 static final class RemoteResource extends Resource
505 private final URL url;
506 private final InputStream stream;
507 private final int length;
509 RemoteResource(RemoteURLLoader loader, String name, URL url,
510 InputStream stream, int length)
514 this.stream = stream;
515 this.length = length;
518 InputStream getInputStream() throws IOException
523 public int getLength()
535 * A <code>SoURLLoader</code> is a type of <code>URLLoader</code>
536 * that loads classes and resources from a shared library.
538 final static class SoURLLoader extends URLLoader
540 SharedLibHelper helper;
542 SoURLLoader(URLClassLoader classloader, URL url)
544 this(classloader, url, url);
547 SoURLLoader(URLClassLoader classloader, URL url, URL overrideURL)
549 super(classloader, url, overrideURL);
550 helper = SharedLibHelper.findHelper(classloader, url.getFile(),
551 noCertCodeSource, true);
554 Class getClass(String className)
556 return helper.findClass(className);
559 Resource getResource(String name)
561 URL url = helper.findResource(name);
564 return new SoResource(this, name, url);
568 final static class SoResource extends Resource
570 SoResource(SoURLLoader loader, String name, URL url)
576 InputStream getInputStream() throws IOException
578 URLConnection conn = url.openConnection();
579 return conn.getInputStream();
582 public int getLength()
584 // FIXME we could find this by asking the core object.
597 * A <code>FileURLLoader</code> is a type of <code>URLLoader</code>
598 * only loading from file url.
600 static final class FileURLLoader extends URLLoader
602 File dir; //the file for this file url
604 FileURLLoader(URLClassLoader classloader, URL url)
606 super(classloader, url);
607 dir = new File(baseURL.getFile());
610 /** get resource with the name "name" in the file url */
611 Resource getResource(String name)
615 File file = new File(dir, name).getCanonicalFile();
616 if (file.exists() && !file.isDirectory())
617 return new FileResource(this, file.getPath(), file);
619 catch (IOException e)
627 static final class FileResource extends Resource
631 FileResource(FileURLLoader loader, String name, File file)
637 InputStream getInputStream() throws IOException
639 // Delegate to the URL content handler mechanism to retrieve an
640 // HTML representation of the directory listing if a directory
641 if (file.isDirectory())
644 return url.openStream();
646 // Otherwise simply return a FileInputStream
647 return new FileInputStream(file);
650 public int getLength()
652 // Delegate to the URL content handler mechanism to retrieve the
653 // length of the HTML representation of the directory listing if
654 // a directory, or -1 if an exception occurs opening the directory.
655 if (file.isDirectory())
660 URLConnection connection = url.openConnection();
661 return connection.getContentLength();
663 catch (IOException e)
668 // Otherwise simply return the file length
669 return (int) file.length();
676 return new URL(loader.baseURL, name,
677 loader.classloader.getURLStreamHandler("file"));
679 catch (MalformedURLException e)
681 InternalError ie = new InternalError();
689 * A <code>CoreURLLoader</code> is a type of <code>URLLoader</code>
690 * only loading from core url.
692 static final class CoreURLLoader extends URLLoader
696 CoreURLLoader(URLClassLoader classloader, URL url)
698 super(classloader, url);
699 dir = baseURL.getFile();
702 /** get resource with the name "name" in the core url */
703 Resource getResource(String name)
705 Core core = Core.find (dir + name);
707 return new CoreResource(this, name, core);
712 static final class CoreResource extends Resource
716 CoreResource(CoreURLLoader loader, String name, Core core)
722 InputStream getInputStream() throws IOException
724 return new CoreInputStream(core);
727 public int getLength()
736 return new URL(loader.baseURL, name,
737 loader.classloader.getURLStreamHandler("core"));
739 catch (MalformedURLException e)
741 InternalError ie = new InternalError();
751 * Creates a URLClassLoader that gets classes from the supplied URLs.
752 * To determine if this classloader may be created the constructor of
753 * the super class (<code>SecureClassLoader</code>) is called first, which
754 * can throw a SecurityException. Then the supplied URLs are added
755 * in the order given to the URLClassLoader which uses these URLs to
756 * load classes and resources (after using the default parent ClassLoader).
758 * @exception SecurityException if the SecurityManager disallows the
759 * creation of a ClassLoader.
760 * @param urls Locations that should be searched by this ClassLoader when
761 * resolving Classes or Resources.
762 * @see SecureClassLoader
764 public URLClassLoader(URL[] urls) throws SecurityException
768 this.securityContext = null;
773 * Private constructor used by the static
774 * <code>newInstance(URL[])</code> method. Creates an
775 * <code>URLClassLoader</code> without any <code>URL</code>s
776 * yet. This is used to bypass the normal security check for
777 * creating classloaders, but remembers the security context which
778 * will be used when defining classes. The <code>URL</code>s to
779 * load from must be added by the <code>newInstance()</code> method
780 * in the security context of the caller.
782 * @param securityContext the security context of the unprivileged code.
784 private URLClassLoader(AccessControlContext securityContext)
788 this.securityContext = securityContext;
792 * Creates a <code>URLClassLoader</code> that gets classes from the supplied
794 * To determine if this classloader may be created the constructor of
795 * the super class (<code>SecureClassLoader</code>) is called first, which
796 * can throw a SecurityException. Then the supplied URLs are added
797 * in the order given to the URLClassLoader which uses these URLs to
798 * load classes and resources (after using the supplied parent ClassLoader).
799 * @exception SecurityException if the SecurityManager disallows the
800 * creation of a ClassLoader.
801 * @exception SecurityException
802 * @param urls Locations that should be searched by this ClassLoader when
803 * resolving Classes or Resources.
804 * @param parent The parent class loader used before trying this class
806 * @see SecureClassLoader
808 public URLClassLoader(URL[] urls, ClassLoader parent)
809 throws SecurityException
813 this.securityContext = null;
817 // Package-private to avoid a trampoline constructor.
819 * Package-private constructor used by the static
820 * <code>newInstance(URL[])</code> method. Creates an
821 * <code>URLClassLoader</code> with the given parent but without any
822 * <code>URL</code>s yet. This is used to bypass the normal security
823 * check for creating classloaders, but remembers the security
824 * context which will be used when defining classes. The
825 * <code>URL</code>s to load from must be added by the
826 * <code>newInstance()</code> method in the security context of the
829 * @param securityContext the security context of the unprivileged code.
831 URLClassLoader(ClassLoader parent, AccessControlContext securityContext)
835 this.securityContext = securityContext;
839 * Creates a URLClassLoader that gets classes from the supplied URLs.
840 * To determine if this classloader may be created the constructor of
841 * the super class (<CODE>SecureClassLoader</CODE>) is called first, which
842 * can throw a SecurityException. Then the supplied URLs are added
843 * in the order given to the URLClassLoader which uses these URLs to
844 * load classes and resources (after using the supplied parent ClassLoader).
845 * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the
846 * protocol handlers of the supplied URLs.
847 * @exception SecurityException if the SecurityManager disallows the
848 * creation of a ClassLoader.
849 * @exception SecurityException
850 * @param urls Locations that should be searched by this ClassLoader when
851 * resolving Classes or Resources.
852 * @param parent The parent class loader used before trying this class
854 * @param factory Used to get the protocol handler for the URLs.
855 * @see SecureClassLoader
857 public URLClassLoader(URL[] urls, ClassLoader parent,
858 URLStreamHandlerFactory factory)
859 throws SecurityException
862 this.securityContext = null;
863 this.factory = factory;
866 // If this factory is still not in factoryCache, add it,
867 // since we only support three protocols so far, 5 is enough
868 // for cache initial size
869 synchronized (factoryCache)
871 if (factory != null && factoryCache.get(factory) == null)
872 factoryCache.put(factory, new HashMap(5));
879 * Adds a new location to the end of the internal URL store.
880 * @param newUrl the location to add
882 protected void addURL(URL newUrl)
888 private void addURLImpl(URL newUrl)
893 return; // Silently ignore...
895 // Reset the toString() value.
898 // Check global cache to see if there're already url loader
900 URLLoader loader = (URLLoader) urlloaders.get(newUrl);
903 String file = newUrl.getFile();
904 String protocol = newUrl.getProtocol();
906 // Check that it is not a directory
907 if ("gcjlib".equals(protocol))
908 loader = new SoURLLoader(this, newUrl);
909 else if (! (file.endsWith("/") || file.endsWith(File.separator)))
910 loader = new JarURLLoader(this, newUrl);
911 else if ("file".equals(protocol))
912 loader = new FileURLLoader(this, newUrl);
913 else if ("core".equals(protocol))
914 loader = new CoreURLLoader(this, newUrl);
916 loader = new RemoteURLLoader(this, newUrl);
919 urlloaders.put(newUrl, loader);
922 urlinfos.add(loader);
924 Vector extraUrls = loader.getClassPath();
925 if (extraUrls != null)
927 Iterator it = extraUrls.iterator();
930 URL url = (URL)it.next();
931 URLLoader extraLoader = (URLLoader) urlloaders.get(url);
932 if (! urlinfos.contains (extraLoader))
941 * Adds an array of new locations to the end of the internal URL store.
942 * @param newUrls the locations to add
944 private void addURLs(URL[] newUrls)
946 for (int i = 0; i < newUrls.length; i++)
951 * Look in both Attributes for a given value. The first Attributes
952 * object, if not null, has precedence.
954 private String getAttributeValue(Attributes.Name name, Attributes first,
957 String result = null;
959 result = first.getValue(name);
961 result = second.getValue(name);
966 * Defines a Package based on the given name and the supplied manifest
967 * information. The manifest indicates the title, version and
968 * vendor information of the specification and implementation and whether the
969 * package is sealed. If the Manifest indicates that the package is sealed
970 * then the Package will be sealed with respect to the supplied URL.
972 * @exception IllegalArgumentException If this package name already exists
973 * in this class loader
974 * @param name The name of the package
975 * @param manifest The manifest describing the specification,
976 * implementation and sealing details of the package
977 * @param url the code source url to seal the package
978 * @return the defined Package
980 protected Package definePackage(String name, Manifest manifest, URL url)
981 throws IllegalArgumentException
983 // Compute the name of the package as it may appear in the
985 StringBuffer xform = new StringBuffer(name);
986 for (int i = xform.length () - 1; i >= 0; --i)
987 if (xform.charAt(i) == '.')
988 xform.setCharAt(i, '/');
990 String xformName = xform.toString();
992 Attributes entryAttr = manifest.getAttributes(xformName);
993 Attributes attr = manifest.getMainAttributes();
996 = getAttributeValue(Attributes.Name.SPECIFICATION_TITLE,
999 = getAttributeValue(Attributes.Name.SPECIFICATION_VERSION,
1002 = getAttributeValue(Attributes.Name.SPECIFICATION_VENDOR,
1005 = getAttributeValue(Attributes.Name.IMPLEMENTATION_TITLE,
1008 = getAttributeValue(Attributes.Name.IMPLEMENTATION_VERSION,
1011 = getAttributeValue(Attributes.Name.IMPLEMENTATION_VENDOR,
1014 // Look if the Manifest indicates that this package is sealed
1015 // XXX - most likely not completely correct!
1016 // Shouldn't we also check the sealed attribute of the complete jar?
1017 // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled
1018 // But how do we get that jar manifest here?
1019 String sealed = attr.getValue(Attributes.Name.SEALED);
1020 if ("false".equals(sealed))
1021 // make sure that the URL is null so the package is not sealed
1024 return definePackage(name,
1025 specTitle, specVendor, specVersion,
1026 implTitle, implVendor, implVersion,
1031 * Finds (the first) class by name from one of the locations. The locations
1032 * are searched in the order they were added to the URLClassLoader.
1034 * @param className the classname to find
1035 * @exception ClassNotFoundException when the class could not be found or
1037 * @return a Class object representing the found class
1039 protected Class findClass(final String className)
1040 throws ClassNotFoundException
1042 // Just try to find the resource by the (almost) same name
1043 String resourceName = className.replace('.', '/') + ".class";
1044 int max = urlinfos.size();
1045 Resource resource = null;
1046 for (int i = 0; i < max && resource == null; i++)
1048 URLLoader loader = (URLLoader)urlinfos.elementAt(i);
1052 Class k = loader.getClass(className);
1056 resource = loader.getResource(resourceName);
1058 if (resource == null)
1059 throw new ClassNotFoundException(className + " not found in " + this);
1061 // Try to read the class data, create the CodeSource, Package and
1062 // construct the class (and watch out for those nasty IOExceptions)
1066 InputStream in = resource.getInputStream();
1067 int length = resource.getLength();
1070 // We know the length of the data.
1071 // Just try to read it in all at once
1072 data = new byte[length];
1074 while (length - pos > 0)
1076 int len = in.read(data, pos, length - pos);
1078 throw new EOFException("Not enough data reading from: "
1085 // We don't know the data length.
1086 // Have to read it in chunks.
1087 ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
1088 byte[] b = new byte[4096];
1096 data = out.toByteArray();
1098 final byte[] classData = data;
1100 // Now get the CodeSource
1101 final CodeSource source = resource.getCodeSource();
1103 // Find out package name
1104 String packageName = null;
1105 int lastDot = className.lastIndexOf('.');
1107 packageName = className.substring(0, lastDot);
1109 if (packageName != null && getPackage(packageName) == null)
1111 // define the package
1112 Manifest manifest = resource.loader.getManifest();
1113 if (manifest == null)
1114 definePackage(packageName, null, null, null, null, null, null,
1117 definePackage(packageName, manifest, resource.loader.baseURL);
1120 // And finally construct the class!
1121 SecurityManager sm = System.getSecurityManager();
1122 Class result = null;
1123 if (sm != null && securityContext != null)
1125 result = (Class)AccessController.doPrivileged
1126 (new PrivilegedAction()
1130 return defineClass(className, classData,
1131 0, classData.length,
1134 }, securityContext);
1137 result = defineClass(className, classData, 0, classData.length, source);
1139 super.setSigners(result, resource.getCertificates());
1142 catch (IOException ioe)
1144 ClassNotFoundException cnfe;
1145 cnfe = new ClassNotFoundException(className + " not found in " + this);
1146 cnfe.initCause(ioe);
1151 // Cached String representation of this URLClassLoader
1152 private String thisString;
1155 * Returns a String representation of this URLClassLoader giving the
1156 * actual Class name, the URLs that are searched and the parent
1159 public String toString()
1163 if (thisString == null)
1165 StringBuffer sb = new StringBuffer();
1166 sb.append(this.getClass().getName());
1167 sb.append("{urls=[" );
1168 URL[] thisURLs = getURLs();
1169 for (int i = 0; i < thisURLs.length; i++)
1171 sb.append(thisURLs[i]);
1172 if (i < thisURLs.length - 1)
1176 sb.append(", parent=");
1177 sb.append(getParent());
1179 thisString = sb.toString();
1186 * Finds the first occurrence of a resource that can be found. The locations
1187 * are searched in the order they were added to the URLClassLoader.
1189 * @param resourceName the resource name to look for
1190 * @return the URLResource for the resource if found, null otherwise
1192 private Resource findURLResource(String resourceName)
1194 int max = urlinfos.size();
1195 for (int i = 0; i < max; i++)
1197 URLLoader loader = (URLLoader) urlinfos.elementAt(i);
1201 Resource resource = loader.getResource(resourceName);
1202 if (resource != null)
1209 * Finds the first occurrence of a resource that can be found.
1211 * @param resourceName the resource name to look for
1212 * @return the URL if found, null otherwise
1214 public URL findResource(String resourceName)
1216 Resource resource = findURLResource(resourceName);
1217 if (resource != null)
1218 return resource.getURL();
1220 // Resource not found
1225 * If the URLStreamHandlerFactory has been set this return the appropriate
1226 * URLStreamHandler for the given protocol, if not set returns null.
1228 * @param protocol the protocol for which we need a URLStreamHandler
1229 * @return the appropriate URLStreamHandler or null
1231 URLStreamHandler getURLStreamHandler(String protocol)
1233 if (factory == null)
1236 URLStreamHandler handler;
1237 synchronized (factoryCache)
1239 // Check if there're handler for the same protocol in cache.
1240 HashMap cache = (HashMap) factoryCache.get(factory);
1241 handler = (URLStreamHandler) cache.get(protocol);
1242 if (handler == null)
1245 handler = factory.createURLStreamHandler(protocol);
1246 cache.put(protocol, handler);
1253 * Finds all the resources with a particular name from all the locations.
1255 * @exception IOException when an error occurs accessing one of the
1257 * @param resourceName the name of the resource to lookup
1258 * @return a (possible empty) enumeration of URLs where the resource can be
1261 public Enumeration findResources(String resourceName)
1264 Vector resources = new Vector();
1265 int max = urlinfos.size();
1266 for (int i = 0; i < max; i++)
1268 URLLoader loader = (URLLoader) urlinfos.elementAt(i);
1269 Resource resource = loader.getResource(resourceName);
1270 if (resource != null)
1271 resources.add(resource.getURL());
1273 return resources.elements();
1277 * Returns the permissions needed to access a particular code
1278 * source. These permissions includes those returned by
1279 * <code>SecureClassLoader.getPermissions()</code> and the actual
1280 * permissions to access the objects referenced by the URL of the
1281 * code source. The extra permissions added depend on the protocol
1282 * and file portion of the URL in the code source. If the URL has
1283 * the "file" protocol ends with a '/' character then it must be a
1284 * directory and a file Permission to read everything in that
1285 * directory and all subdirectories is added. If the URL had the
1286 * "file" protocol and doesn't end with a '/' character then it must
1287 * be a normal file and a file permission to read that file is
1288 * added. If the <code>URL</code> has any other protocol then a
1289 * socket permission to connect and accept connections from the host
1290 * portion of the URL is added.
1292 * @param source The codesource that needs the permissions to be accessed
1293 * @return the collection of permissions needed to access the code resource
1294 * @see java.security.SecureClassLoader#getPermissions()
1296 protected PermissionCollection getPermissions(CodeSource source)
1298 // XXX - This implementation does exactly as the Javadoc describes.
1299 // But maybe we should/could use URLConnection.getPermissions()?
1300 // First get the permissions that would normally be granted
1301 PermissionCollection permissions = super.getPermissions(source);
1303 // Now add any extra permissions depending on the URL location.
1304 URL url = source.getLocation();
1305 String protocol = url.getProtocol();
1306 if (protocol.equals("file"))
1308 String file = url.getFile();
1310 // If the file end in / it must be an directory.
1311 if (file.endsWith("/") || file.endsWith(File.separator))
1313 // Grant permission to read everything in that directory and
1314 // all subdirectories.
1315 permissions.add(new FilePermission(file + "-", "read"));
1319 // It is a 'normal' file.
1320 // Grant permission to access that file.
1321 permissions.add(new FilePermission(file, "read"));
1326 // Grant permission to connect to and accept connections from host
1327 String host = url.getHost();
1329 permissions.add(new SocketPermission(host, "connect,accept"));
1336 * Returns all the locations that this class loader currently uses the
1337 * resolve classes and resource. This includes both the initially supplied
1338 * URLs as any URLs added later by the loader.
1339 * @return All the currently used URLs
1341 public URL[] getURLs()
1343 return (URL[]) urls.toArray(new URL[urls.size()]);
1347 * Creates a new instance of a <code>URLClassLoader</code> that gets
1348 * classes from the supplied <code>URL</code>s. This class loader
1349 * will have as parent the standard system class loader.
1351 * @param urls the initial URLs used to resolve classes and
1354 * @return the class loader
1356 * @exception SecurityException when the calling code does not have
1357 * permission to access the given <code>URL</code>s
1359 public static URLClassLoader newInstance(URL[] urls)
1360 throws SecurityException
1362 return newInstance(urls, null);
1366 * Creates a new instance of a <code>URLClassLoader</code> that gets
1367 * classes from the supplied <code>URL</code>s and with the supplied
1368 * loader as parent class loader.
1370 * @param urls the initial URLs used to resolve classes and
1372 * @param parent the parent class loader
1374 * @return the class loader
1376 * @exception SecurityException when the calling code does not have
1377 * permission to access the given <code>URL</code>s
1379 public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent)
1380 throws SecurityException
1382 SecurityManager sm = System.getSecurityManager();
1384 return new URLClassLoader(urls, parent);
1387 final Object securityContext = sm.getSecurityContext();
1389 // XXX - What to do with anything else then an AccessControlContext?
1390 if (! (securityContext instanceof AccessControlContext))
1391 throw new SecurityException("securityContext must be AccessControlContext: "
1394 URLClassLoader loader =
1395 (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction()
1399 return new URLClassLoader(parent,
1400 (AccessControlContext) securityContext);
1403 loader.addURLs(urls);