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., 59 Temple Place, Suite 330, 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;
69 * A secure class loader that can load classes and resources from
70 * multiple locations. Given an array of <code>URL</code>s this class
71 * loader will retrieve classes and resources by fetching them from
72 * possible remote locations. Each <code>URL</code> is searched in
73 * order in which it was added. If the file portion of the
74 * <code>URL</code> ends with a '/' character then it is interpreted
75 * as a base directory, otherwise it is interpreted as a jar file from
76 * which the classes/resources are resolved.
78 * <p>New instances can be created by two static
79 * <code>newInstance()</code> methods or by three public
80 * contructors. Both ways give the option to supply an initial array
81 * of <code>URL</code>s and (optionally) a parent classloader (that is
82 * different from the standard system class loader).</p>
84 * <p>Normally creating a <code>URLClassLoader</code> throws a
85 * <code>SecurityException</code> if a <code>SecurityManager</code> is
86 * installed and the <code>checkCreateClassLoader()</code> method does
87 * not return true. But the <code>newInstance()</code> methods may be
88 * used by any code as long as it has permission to acces the given
89 * <code>URL</code>s. <code>URLClassLoaders</code> created by the
90 * <code>newInstance()</code> methods also explicitly call the
91 * <code>checkPackageAccess()</code> method of
92 * <code>SecurityManager</code> if one is installed before trying to
93 * load a class. Note that only subclasses of
94 * <code>URLClassLoader</code> can add new URLs after the
95 * URLClassLoader had been created. But it is always possible to get
96 * an array of all URLs that the class loader uses to resolve classes
97 * and resources by way of the <code>getURLs()</code> method.</p>
102 * <li>Should the URLClassLoader actually add the locations found in
103 * the manifest or is this the responsibility of some other
104 * loader/(sub)class? (see <a
105 * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html">
106 * Extension Mechanism Architecture - Bundles Extensions</a>)</li>
108 * <li>How does <code>definePackage()</code> and sealing work
111 * <li>We save and use the security context (when a created by
112 * <code>newInstance()</code> but do we have to use it in more
115 * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li>
122 * @author Mark Wielaard (mark@klomp.org)
123 * @author Wu Gansha (gansha.wu@intel.com)
125 public class URLClassLoader extends SecureClassLoader
130 * A global cache to store mappings between URLLoader and URL,
131 * so we can avoid do all the homework each time the same URL
133 * XXX - Keeps these loaders forever which prevents garbage collection.
135 private static HashMap urlloaders = new HashMap();
138 * A cache to store mappings between handler factory and its
139 * private protocol handler cache (also a HashMap), so we can avoid
140 * create handlers each time the same protocol comes.
142 private static HashMap factoryCache = new HashMap(5);
144 // Instance variables
146 /** Locations to load classes from */
147 private final Vector urls = new Vector();
150 * Store pre-parsed information for each url into this vector: each
151 * element is a URL loader. A jar file has its own class-path
152 * attribute which adds to the URLs that will be searched, but this
153 * does not add to the list of urls.
155 private final Vector urlinfos = new Vector();
157 /** Factory used to get the protocol handlers of the URLs */
158 private final URLStreamHandlerFactory factory;
161 * The security context when created from <code>newInstance()</code>
162 * or null when created through a normal constructor or when no
163 * <code>SecurityManager</code> was installed.
165 private final AccessControlContext securityContext;
170 * A <code>URLLoader</code> contains all logic to load resources from a
171 * given base <code>URL</code>.
173 abstract static class URLLoader
176 * Our classloader to get info from if needed.
178 final URLClassLoader classloader;
181 * The base URL from which all resources are loaded.
186 * A <code>CodeSource</code> without any associated certificates.
187 * It is common for classes to not have certificates associated
188 * with them. If they come from the same <code>URLLoader</code>
189 * then it is safe to share the associated <code>CodeSource</code>
190 * between them since <code>CodeSource</code> is immutable.
192 final CodeSource noCertCodeSource;
194 URLLoader(URLClassLoader classloader, URL baseURL)
196 this(classloader, baseURL, baseURL);
199 URLLoader(URLClassLoader classloader, URL baseURL, URL overrideURL)
201 this.classloader = classloader;
202 this.baseURL = baseURL;
203 this.noCertCodeSource = new CodeSource(overrideURL, null);
207 * Returns a <code>Class</code> loaded by this
208 * <code>URLLoader</code>, or <code>null</code> when this loader
209 * either can't load the class or doesn't know how to load classes
212 Class getClass(String className)
218 * Returns a <code>Resource</code> loaded by this
219 * <code>URLLoader</code>, or <code>null</code> when no
220 * <code>Resource</code> with the given name exists.
222 abstract Resource getResource(String s);
225 * Returns the <code>Manifest</code> associated with the
226 * <code>Resource</code>s loaded by this <code>URLLoader</code> or
227 * <code>null</code> there is no such <code>Manifest</code>.
229 Manifest getManifest()
234 Vector getClassPath()
241 * A <code>Resource</code> represents a resource in some
242 * <code>URLLoader</code>. It also contains all information (e.g.,
243 * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and
244 * <code>InputStream</code>) that is necessary for loading resources
245 * and creating classes from a <code>URL</code>.
247 abstract static class Resource
249 final URLLoader loader;
252 Resource(URLLoader loader, String name)
254 this.loader = loader;
259 * Returns the non-null <code>CodeSource</code> associated with
262 CodeSource getCodeSource()
264 Certificate[] certs = getCertificates();
266 return loader.noCertCodeSource;
268 return new CodeSource(loader.baseURL, certs);
272 * Returns <code>Certificates</code> associated with this
273 * resource, or null when there are none.
275 Certificate[] getCertificates()
281 * Return a <code>URL</code> that can be used to access this resource.
283 abstract URL getURL();
286 * Returns the size of this <code>Resource</code> in bytes or
287 * <code>-1</code> when unknown.
289 abstract int getLength();
292 * Returns the non-null <code>InputStream</code> through which
293 * this resource can be loaded.
295 abstract InputStream getInputStream() throws IOException;
299 * A <code>JarURLLoader</code> is a type of <code>URLLoader</code>
300 * only loading from jar url.
302 static final class JarURLLoader extends URLLoader
304 final JarFile jarfile; // The jar file for this url
305 final URL baseJarURL; // Base jar: url for all resources loaded from jar
307 Vector classPath; // The "Class-Path" attribute of this Jar's manifest
309 public JarURLLoader(URLClassLoader classloader, URL baseURL)
311 super(classloader, baseURL);
313 // Cache url prefix for all resources in this jar url.
314 String external = baseURL.toExternalForm();
315 StringBuffer sb = new StringBuffer(external.length() + 6);
319 String jarURL = sb.toString();
321 this.classPath = null;
322 URL baseJarURL = null;
323 JarFile jarfile = null;
327 new URL(null, jarURL, classloader.getURLStreamHandler("jar"));
330 ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
333 Attributes attributes;
334 String classPathString;
336 if ((manifest = jarfile.getManifest()) != null
337 && (attributes = manifest.getMainAttributes()) != null
339 = attributes.getValue(Attributes.Name.CLASS_PATH))
342 this.classPath = new Vector();
344 StringTokenizer st = new StringTokenizer(classPathString, " ");
345 while (st.hasMoreElements ())
347 String e = st.nextToken ();
350 URL url = new URL(baseURL, e);
351 this.classPath.add(url);
353 catch (java.net.MalformedURLException xx)
360 catch (IOException ioe)
365 this.baseJarURL = baseJarURL;
366 this.jarfile = jarfile;
369 /** get resource with the name "name" in the jar url */
370 Resource getResource(String name)
375 if (name.startsWith("/"))
376 name = name.substring(1);
378 JarEntry je = jarfile.getJarEntry(name);
380 return new JarURLResource(this, name, je);
385 Manifest getManifest()
389 return (jarfile == null) ? null : jarfile.getManifest();
391 catch (IOException ioe)
397 Vector getClassPath()
403 static final class JarURLResource extends Resource
405 private final JarEntry entry;
407 JarURLResource(JarURLLoader loader, String name, JarEntry entry)
413 InputStream getInputStream() throws IOException
415 return ((JarURLLoader) loader).jarfile.getInputStream(entry);
420 return (int) entry.getSize();
423 Certificate[] getCertificates()
425 return entry.getCertificates();
432 return new URL(((JarURLLoader) loader).baseJarURL, name,
433 loader.classloader.getURLStreamHandler("jar"));
435 catch (MalformedURLException e)
437 InternalError ie = new InternalError();
445 * Loader for remote directories.
447 static final class RemoteURLLoader extends URLLoader
449 private final String protocol;
451 RemoteURLLoader(URLClassLoader classloader, URL url)
453 super(classloader, url);
454 protocol = url.getProtocol();
458 * Get a remote resource.
459 * Returns null if no such resource exists.
461 Resource getResource(String name)
466 new URL(baseURL, name, classloader.getURLStreamHandler(protocol));
467 URLConnection connection = url.openConnection();
469 // Open the connection and check the stream
470 // just to be sure it exists.
471 int length = connection.getContentLength();
472 InputStream stream = connection.getInputStream();
474 // We can do some extra checking if it is a http request
475 if (connection instanceof HttpURLConnection)
478 ((HttpURLConnection) connection).getResponseCode();
479 if (response / 100 != 2)
484 return new RemoteResource(this, name, url, stream, length);
488 catch (IOException ioe)
496 * A resource from some remote location.
498 static final class RemoteResource extends Resource
500 private final URL url;
501 private final InputStream stream;
502 private final int length;
504 RemoteResource(RemoteURLLoader loader, String name, URL url,
505 InputStream stream, int length)
509 this.stream = stream;
510 this.length = length;
513 InputStream getInputStream() throws IOException
518 public int getLength()
530 * A <code>SoURLLoader</code> is a type of <code>URLLoader</code>
531 * that loads classes and resources from a shared library.
533 final static class SoURLLoader extends URLLoader
535 SharedLibHelper helper;
537 SoURLLoader(URLClassLoader classloader, URL url)
539 this(classloader, url, url);
542 SoURLLoader(URLClassLoader classloader, URL url, URL overrideURL)
544 super(classloader, url, overrideURL);
545 helper = SharedLibHelper.findHelper(classloader, url.getFile(),
546 noCertCodeSource, true);
549 Class getClass(String className)
551 return helper.findClass(className);
554 Resource getResource(String name)
556 URL url = helper.findResource(name);
559 return new SoResource(this, name, url);
563 final static class SoResource extends Resource
565 SoResource(SoURLLoader loader, String name, URL url)
571 InputStream getInputStream() throws IOException
573 URLConnection conn = url.openConnection();
574 return conn.getInputStream();
577 public int getLength()
579 // FIXME we could find this by asking the core object.
592 * A <code>FileURLLoader</code> is a type of <code>URLLoader</code>
593 * only loading from file url.
595 static final class FileURLLoader extends URLLoader
597 File dir; //the file for this file url
599 FileURLLoader(URLClassLoader classloader, URL url)
601 super(classloader, url);
602 dir = new File(baseURL.getFile());
605 /** get resource with the name "name" in the file url */
606 Resource getResource(String name)
608 File file = new File(dir, name);
609 if (file.exists() && ! file.isDirectory())
610 return new FileResource(this, name, file);
615 static final class FileResource extends Resource
619 FileResource(FileURLLoader loader, String name, File file)
625 InputStream getInputStream() throws IOException
627 return new FileInputStream(file);
630 public int getLength()
632 return (int) file.length();
639 return new URL(loader.baseURL, name,
640 loader.classloader.getURLStreamHandler("file"));
642 catch (MalformedURLException e)
644 InternalError ie = new InternalError();
654 * Creates a URLClassLoader that gets classes from the supplied URLs.
655 * To determine if this classloader may be created the constructor of
656 * the super class (<code>SecureClassLoader</code>) is called first, which
657 * can throw a SecurityException. Then the supplied URLs are added
658 * in the order given to the URLClassLoader which uses these URLs to
659 * load classes and resources (after using the default parent ClassLoader).
661 * @exception SecurityException if the SecurityManager disallows the
662 * creation of a ClassLoader.
663 * @param urls Locations that should be searched by this ClassLoader when
664 * resolving Classes or Resources.
665 * @see SecureClassLoader
667 public URLClassLoader(URL[] urls) throws SecurityException
671 this.securityContext = null;
676 * Private constructor used by the static
677 * <code>newInstance(URL[])</code> method. Creates an
678 * <code>URLClassLoader</code> without any <code>URL</code>s
679 * yet. This is used to bypass the normal security check for
680 * creating classloaders, but remembers the security context which
681 * will be used when defining classes. The <code>URL</code>s to
682 * load from must be added by the <code>newInstance()</code> method
683 * in the security context of the caller.
685 * @param securityContext the security context of the unprivileged code.
687 private URLClassLoader(AccessControlContext securityContext)
691 this.securityContext = securityContext;
695 * Creates a <code>URLClassLoader</code> that gets classes from the supplied
697 * To determine if this classloader may be created the constructor of
698 * the super class (<code>SecureClassLoader</code>) is called first, which
699 * can throw a SecurityException. Then the supplied URLs are added
700 * in the order given to the URLClassLoader which uses these URLs to
701 * load classes and resources (after using the supplied parent ClassLoader).
702 * @exception SecurityException if the SecurityManager disallows the
703 * creation of a ClassLoader.
704 * @exception SecurityException
705 * @param urls Locations that should be searched by this ClassLoader when
706 * resolving Classes or Resources.
707 * @param parent The parent class loader used before trying this class
709 * @see SecureClassLoader
711 public URLClassLoader(URL[] urls, ClassLoader parent)
712 throws SecurityException
716 this.securityContext = null;
720 // Package-private to avoid a trampoline constructor.
722 * Package-private constructor used by the static
723 * <code>newInstance(URL[])</code> method. Creates an
724 * <code>URLClassLoader</code> with the given parent but without any
725 * <code>URL</code>s yet. This is used to bypass the normal security
726 * check for creating classloaders, but remembers the security
727 * context which will be used when defining classes. The
728 * <code>URL</code>s to load from must be added by the
729 * <code>newInstance()</code> method in the security context of the
732 * @param securityContext the security context of the unprivileged code.
734 URLClassLoader(ClassLoader parent, AccessControlContext securityContext)
738 this.securityContext = securityContext;
742 * Creates a URLClassLoader that gets classes from the supplied URLs.
743 * To determine if this classloader may be created the constructor of
744 * the super class (<CODE>SecureClassLoader</CODE>) is called first, which
745 * can throw a SecurityException. Then the supplied URLs are added
746 * in the order given to the URLClassLoader which uses these URLs to
747 * load classes and resources (after using the supplied parent ClassLoader).
748 * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the
749 * protocol handlers of the supplied URLs.
750 * @exception SecurityException if the SecurityManager disallows the
751 * creation of a ClassLoader.
752 * @exception SecurityException
753 * @param urls Locations that should be searched by this ClassLoader when
754 * resolving Classes or Resources.
755 * @param parent The parent class loader used before trying this class
757 * @param factory Used to get the protocol handler for the URLs.
758 * @see SecureClassLoader
760 public URLClassLoader(URL[] urls, ClassLoader parent,
761 URLStreamHandlerFactory factory)
762 throws SecurityException
765 this.securityContext = null;
766 this.factory = factory;
769 // If this factory is still not in factoryCache, add it,
770 // since we only support three protocols so far, 5 is enough
771 // for cache initial size
772 synchronized (factoryCache)
774 if (factory != null && factoryCache.get(factory) == null)
775 factoryCache.put(factory, new HashMap(5));
782 * Adds a new location to the end of the internal URL store.
783 * @param newUrl the location to add
785 protected void addURL(URL newUrl)
791 private void addURLImpl(URL newUrl)
793 synchronized (urlloaders)
796 return; // Silently ignore...
798 // Check global cache to see if there're already url loader
800 URLLoader loader = (URLLoader) urlloaders.get(newUrl);
803 String file = newUrl.getFile();
804 String protocol = newUrl.getProtocol();
806 // Check that it is not a directory
807 if ("gcjlib".equals(protocol))
808 loader = new SoURLLoader(this, newUrl);
809 else if (! (file.endsWith("/") || file.endsWith(File.separator)))
810 loader = new JarURLLoader(this, newUrl);
811 else if ("file".equals(protocol))
812 loader = new FileURLLoader(this, newUrl);
814 loader = new RemoteURLLoader(this, newUrl);
817 urlloaders.put(newUrl, loader);
820 urlinfos.add(loader);
822 Vector extraUrls = loader.getClassPath();
823 if (extraUrls != null)
825 Iterator it = extraUrls.iterator();
828 URL url = (URL)it.next();
829 URLLoader extraLoader = (URLLoader) urlloaders.get(url);
830 if (! urlinfos.contains (extraLoader))
839 * Adds an array of new locations to the end of the internal URL store.
840 * @param newUrls the locations to add
842 private void addURLs(URL[] newUrls)
844 for (int i = 0; i < newUrls.length; i++)
849 * Defines a Package based on the given name and the supplied manifest
850 * information. The manifest indicates the tile, version and
851 * vendor information of the specification and implementation and wheter the
852 * package is sealed. If the Manifest indicates that the package is sealed
853 * then the Package will be sealed with respect to the supplied URL.
855 * @exception IllegalArgumentException If this package name already exists
856 * in this class loader
857 * @param name The name of the package
858 * @param manifest The manifest describing the specification,
859 * implementation and sealing details of the package
860 * @param url the code source url to seal the package
861 * @return the defined Package
863 protected Package definePackage(String name, Manifest manifest, URL url)
864 throws IllegalArgumentException
866 Attributes attr = manifest.getMainAttributes();
867 String specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
868 String specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
869 String specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
870 String implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
871 String implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
872 String implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
874 // Look if the Manifest indicates that this package is sealed
875 // XXX - most likely not completely correct!
876 // Shouldn't we also check the sealed attribute of the complete jar?
877 // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled
878 // But how do we get that jar manifest here?
879 String sealed = attr.getValue(Attributes.Name.SEALED);
880 if ("false".equals(sealed))
881 // make sure that the URL is null so the package is not sealed
884 return definePackage(name, specTitle, specVersion, specVendor, implTitle,
885 implVersion, implVendor, url);
889 * Finds (the first) class by name from one of the locations. The locations
890 * are searched in the order they were added to the URLClassLoader.
892 * @param className the classname to find
893 * @exception ClassNotFoundException when the class could not be found or
895 * @return a Class object representing the found class
897 protected Class findClass(final String className)
898 throws ClassNotFoundException
900 // Just try to find the resource by the (almost) same name
901 String resourceName = className.replace('.', '/') + ".class";
902 int max = urlinfos.size();
903 Resource resource = null;
904 for (int i = 0; i < max && resource == null; i++)
906 URLLoader loader = (URLLoader)urlinfos.elementAt(i);
910 Class k = loader.getClass(className);
914 resource = loader.getResource(resourceName);
916 if (resource == null)
917 throw new ClassNotFoundException(className + " not found in " + this);
919 // Try to read the class data, create the CodeSource, Package and
920 // construct the class (and watch out for those nasty IOExceptions)
924 InputStream in = resource.getInputStream();
925 int length = resource.getLength();
928 // We know the length of the data.
929 // Just try to read it in all at once
930 data = new byte[length];
932 while (length - pos > 0)
934 int len = in.read(data, pos, length - pos);
936 throw new EOFException("Not enough data reading from: "
943 // We don't know the data length.
944 // Have to read it in chunks.
945 ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
946 byte[] b = new byte[4096];
954 data = out.toByteArray();
956 final byte[] classData = data;
958 // Now get the CodeSource
959 final CodeSource source = resource.getCodeSource();
961 // Find out package name
962 String packageName = null;
963 int lastDot = className.lastIndexOf('.');
965 packageName = className.substring(0, lastDot);
967 if (packageName != null && getPackage(packageName) == null)
969 // define the package
970 Manifest manifest = resource.loader.getManifest();
971 if (manifest == null)
972 definePackage(packageName, null, null, null, null, null, null,
975 definePackage(packageName, manifest, resource.loader.baseURL);
978 // And finally construct the class!
979 SecurityManager sm = System.getSecurityManager();
980 if (sm != null && securityContext != null)
982 return (Class)AccessController.doPrivileged
983 (new PrivilegedAction()
987 return defineClass(className, classData,
994 return defineClass(className, classData, 0, classData.length, source);
996 catch (IOException ioe)
998 ClassNotFoundException cnfe;
999 cnfe = new ClassNotFoundException(className + " not found in " + this);
1000 cnfe.initCause(ioe);
1005 // Cached String representation of this URLClassLoader
1006 private String thisString;
1009 * Returns a String representation of this URLClassLoader giving the
1010 * actual Class name, the URLs that are searched and the parent
1013 public String toString()
1015 if (thisString == null)
1017 StringBuffer sb = new StringBuffer();
1018 sb.append(this.getClass().getName());
1019 sb.append("{urls=[" );
1020 URL[] thisURLs = getURLs();
1021 for (int i = 0; i < thisURLs.length; i++)
1023 sb.append(thisURLs[i]);
1024 if (i < thisURLs.length - 1)
1028 sb.append(", parent=");
1029 sb.append(getParent());
1031 thisString = sb.toString();
1037 * Finds the first occurrence of a resource that can be found. The locations
1038 * are searched in the order they were added to the URLClassLoader.
1040 * @param resourceName the resource name to look for
1041 * @return the URLResource for the resource if found, null otherwise
1043 private Resource findURLResource(String resourceName)
1045 int max = urlinfos.size();
1046 for (int i = 0; i < max; i++)
1048 URLLoader loader = (URLLoader) urlinfos.elementAt(i);
1052 Resource resource = loader.getResource(resourceName);
1053 if (resource != null)
1060 * Finds the first occurrence of a resource that can be found.
1062 * @param resourceName the resource name to look for
1063 * @return the URL if found, null otherwise
1065 public URL findResource(String resourceName)
1067 Resource resource = findURLResource(resourceName);
1068 if (resource != null)
1069 return resource.getURL();
1071 // Resource not found
1076 * If the URLStreamHandlerFactory has been set this return the appropriate
1077 * URLStreamHandler for the given protocol, if not set returns null.
1079 * @param protocol the protocol for which we need a URLStreamHandler
1080 * @return the appropriate URLStreamHandler or null
1082 URLStreamHandler getURLStreamHandler(String protocol)
1084 if (factory == null)
1087 URLStreamHandler handler;
1088 synchronized (factoryCache)
1090 // Check if there're handler for the same protocol in cache.
1091 HashMap cache = (HashMap) factoryCache.get(factory);
1092 handler = (URLStreamHandler) cache.get(protocol);
1093 if (handler == null)
1096 handler = factory.createURLStreamHandler(protocol);
1097 cache.put(protocol, handler);
1104 * Finds all the resources with a particular name from all the locations.
1106 * @exception IOException when an error occurs accessing one of the
1108 * @param resourceName the name of the resource to lookup
1109 * @return a (possible empty) enumeration of URLs where the resource can be
1112 public Enumeration findResources(String resourceName)
1115 Vector resources = new Vector();
1116 int max = urlinfos.size();
1117 for (int i = 0; i < max; i++)
1119 URLLoader loader = (URLLoader) urlinfos.elementAt(i);
1120 Resource resource = loader.getResource(resourceName);
1121 if (resource != null)
1122 resources.add(resource.getURL());
1124 return resources.elements();
1128 * Returns the permissions needed to access a particular code
1129 * source. These permissions includes those returned by
1130 * <code>SecureClassLoader.getPermissions()</code> and the actual
1131 * permissions to access the objects referenced by the URL of the
1132 * code source. The extra permissions added depend on the protocol
1133 * and file portion of the URL in the code source. If the URL has
1134 * the "file" protocol ends with a '/' character then it must be a
1135 * directory and a file Permission to read everything in that
1136 * directory and all subdirectories is added. If the URL had the
1137 * "file" protocol and doesn't end with a '/' character then it must
1138 * be a normal file and a file permission to read that file is
1139 * added. If the <code>URL</code> has any other protocol then a
1140 * socket permission to connect and accept connections from the host
1141 * portion of the URL is added.
1143 * @param source The codesource that needs the permissions to be accessed
1144 * @return the collection of permissions needed to access the code resource
1145 * @see java.security.SecureClassLoader#getPermissions()
1147 protected PermissionCollection getPermissions(CodeSource source)
1149 // XXX - This implementation does exactly as the Javadoc describes.
1150 // But maybe we should/could use URLConnection.getPermissions()?
1151 // First get the permissions that would normally be granted
1152 PermissionCollection permissions = super.getPermissions(source);
1154 // Now add any extra permissions depending on the URL location.
1155 URL url = source.getLocation();
1156 String protocol = url.getProtocol();
1157 if (protocol.equals("file"))
1159 String file = url.getFile();
1161 // If the file end in / it must be an directory.
1162 if (file.endsWith("/") || file.endsWith(File.separator))
1164 // Grant permission to read everything in that directory and
1165 // all subdirectories.
1166 permissions.add(new FilePermission(file + "-", "read"));
1170 // It is a 'normal' file.
1171 // Grant permission to access that file.
1172 permissions.add(new FilePermission(file, "read"));
1177 // Grant permission to connect to and accept connections from host
1178 String host = url.getHost();
1180 permissions.add(new SocketPermission(host, "connect,accept"));
1187 * Returns all the locations that this class loader currently uses the
1188 * resolve classes and resource. This includes both the initially supplied
1189 * URLs as any URLs added later by the loader.
1190 * @return All the currently used URLs
1192 public URL[] getURLs()
1194 return (URL[]) urls.toArray(new URL[urls.size()]);
1198 * Creates a new instance of a <code>URLClassLoader</code> that gets
1199 * classes from the supplied <code>URL</code>s. This class loader
1200 * will have as parent the standard system class loader.
1202 * @param urls the initial URLs used to resolve classes and
1205 * @return the class loader
1207 * @exception SecurityException when the calling code does not have
1208 * permission to access the given <code>URL</code>s
1210 public static URLClassLoader newInstance(URL[] urls)
1211 throws SecurityException
1213 return newInstance(urls, null);
1217 * Creates a new instance of a <code>URLClassLoader</code> that gets
1218 * classes from the supplied <code>URL</code>s and with the supplied
1219 * loader as parent class loader.
1221 * @param urls the initial URLs used to resolve classes and
1223 * @param parent the parent class loader
1225 * @return the class loader
1227 * @exception SecurityException when the calling code does not have
1228 * permission to access the given <code>URL</code>s
1230 public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent)
1231 throws SecurityException
1233 SecurityManager sm = System.getSecurityManager();
1235 return new URLClassLoader(urls, parent);
1238 final Object securityContext = sm.getSecurityContext();
1240 // XXX - What to do with anything else then an AccessControlContext?
1241 if (! (securityContext instanceof AccessControlContext))
1242 throw new SecurityException("securityContext must be AccessControlContext: "
1245 URLClassLoader loader =
1246 (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction()
1250 return new URLClassLoader(parent,
1251 (AccessControlContext) securityContext);
1254 loader.addURLs(urls);