Fixes bug libgcj/8170
[official-gcc.git] / libjava / java / net / URLClassLoader.java
blob0da6a0356b2dd2a113759a470dfaf29f38fe0422
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)
10 any later version.
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
20 02111-1307 USA.
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
25 combination.
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. */
40 package java.net;
42 import java.io.ByteArrayOutputStream;
43 import java.io.EOFException;
44 import java.io.File;
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;
68 /**
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>
99 * <p>Open issues:
100 * <ul>
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
109 * precisely?</li>
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
113 * places?</li>
115 * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li>
117 * </ul>
118 * </p>
120 * @since 1.2
122 * @author Mark Wielaard (mark@klomp.org)
123 * @author Wu Gansha (gansha.wu@intel.com)
125 public class URLClassLoader extends SecureClassLoader
127 // Class Variables
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
132 * comes.
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;
167 // Helper classes
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.
183 final URL baseURL;
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
210 * at all.
212 Class getClass(String className)
214 return null;
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()
231 return null;
234 Vector getClassPath()
236 return null;
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;
250 final String name;
252 Resource(URLLoader loader, String name)
254 this.loader = loader;
255 this.name = name;
259 * Returns the non-null <code>CodeSource</code> associated with
260 * this resource.
262 CodeSource getCodeSource()
264 Certificate[] certs = getCertificates();
265 if (certs == null)
266 return loader.noCertCodeSource;
267 else
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()
277 return null;
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 SoURLLoader soURLLoader;
311 public JarURLLoader(URLClassLoader classloader, URL baseURL)
313 super(classloader, baseURL);
315 // Cache url prefix for all resources in this jar url.
316 String external = baseURL.toExternalForm();
317 StringBuffer sb = new StringBuffer(external.length() + 6);
318 sb.append("jar:");
319 sb.append(external);
320 sb.append("!/");
321 String jarURL = sb.toString();
323 this.soURLLoader = null;
324 this.classPath = null;
325 URL baseJarURL = null;
326 JarFile jarfile = null;
329 baseJarURL
330 = new URL(null, jarURL, classloader.getURLStreamHandler("jar"));
331 jarfile
332 = ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
334 if (jarfile != null)
336 String fileName = baseURL.getFile();
337 if (fileName != null)
339 File f = new File(fileName);
340 String libDirName = f.getCanonicalFile().getParent()
341 + File.separator + "GCJLIBS";
342 File libDir = new File(libDirName);
343 if (libDir != null && (libDir.isDirectory()))
345 File soFile = new File (libDirName
346 + File.separator + f.getName()
347 + ".so");
348 if (soFile != null && soFile.isFile())
349 this.soURLLoader
350 = new SoURLLoader (classloader, soFile.toURL(),
351 baseURL);
355 Manifest manifest;
356 Attributes attributes;
357 String classPathString;
359 if ((manifest = jarfile.getManifest()) != null
360 && (attributes = manifest.getMainAttributes()) != null
361 && ((classPathString
362 = attributes.getValue(Attributes.Name.CLASS_PATH))
363 != null))
365 this.classPath = new Vector();
367 StringTokenizer st
368 = new StringTokenizer
369 (classPathString,
370 System.getProperty ("path.separator", ":"));
372 while (st.hasMoreElements ())
374 String e = st.nextToken ();
377 URL url = new URL(baseURL, e);
378 this.classPath.add(url);
380 catch (java.net.MalformedURLException xx)
382 // Give up
388 catch (IOException ioe)
390 /* ignored */
393 this.baseJarURL = baseJarURL;
394 this.jarfile = jarfile;
397 Class getClass(String className)
399 if (soURLLoader != null)
400 return soURLLoader.getClass(className);
401 return null;
404 /** get resource with the name "name" in the jar url */
405 Resource getResource(String name)
407 if (jarfile == null)
408 return null;
410 if (name.startsWith("/"))
411 name = name.substring(1);
413 JarEntry je = jarfile.getJarEntry(name);
414 if (je != null)
415 return new JarURLResource(this, name, je);
416 else
417 return null;
420 public String toString ()
422 return "jarfile " + jarfile.getName();
425 Manifest getManifest()
429 return (jarfile == null) ? null : jarfile.getManifest();
431 catch (IOException ioe)
433 return null;
437 Vector getClassPath()
439 return classPath;
443 static final class JarURLResource extends Resource
445 private final JarEntry entry;
447 JarURLResource(JarURLLoader loader, String name, JarEntry entry)
449 super(loader, name);
450 this.entry = entry;
453 InputStream getInputStream() throws IOException
455 return ((JarURLLoader) loader).jarfile.getInputStream(entry);
458 int getLength()
460 return (int) entry.getSize();
463 Certificate[] getCertificates()
465 return entry.getCertificates();
468 URL getURL()
472 return new URL(((JarURLLoader) loader).baseJarURL, name,
473 loader.classloader.getURLStreamHandler("jar"));
475 catch (MalformedURLException e)
477 InternalError ie = new InternalError();
478 ie.initCause(e);
479 throw ie;
485 * Loader for remote directories.
487 static final class RemoteURLLoader extends URLLoader
489 private final String protocol;
491 RemoteURLLoader(URLClassLoader classloader, URL url)
493 super(classloader, url);
494 protocol = url.getProtocol();
498 * Get a remote resource.
499 * Returns null if no such resource exists.
501 Resource getResource(String name)
505 URL url =
506 new URL(baseURL, name, classloader.getURLStreamHandler(protocol));
507 URLConnection connection = url.openConnection();
509 // Open the connection and check the stream
510 // just to be sure it exists.
511 int length = connection.getContentLength();
512 InputStream stream = connection.getInputStream();
514 // We can do some extra checking if it is a http request
515 if (connection instanceof HttpURLConnection)
517 int response =
518 ((HttpURLConnection) connection).getResponseCode();
519 if (response / 100 != 2)
520 return null;
523 if (stream != null)
524 return new RemoteResource(this, name, url, stream, length);
525 else
526 return null;
528 catch (IOException ioe)
530 return null;
536 * A resource from some remote location.
538 static final class RemoteResource extends Resource
540 private final URL url;
541 private final InputStream stream;
542 private final int length;
544 RemoteResource(RemoteURLLoader loader, String name, URL url,
545 InputStream stream, int length)
547 super(loader, name);
548 this.url = url;
549 this.stream = stream;
550 this.length = length;
553 InputStream getInputStream() throws IOException
555 return stream;
558 public int getLength()
560 return length;
563 public URL getURL()
565 return url;
570 * A <code>SoURLLoader</code> is a type of <code>URLLoader</code>
571 * that loads classes and resources from a shared library.
573 final static class SoURLLoader extends URLLoader
575 SharedLibHelper helper;
577 SoURLLoader(URLClassLoader classloader, URL url)
579 this(classloader, url, url);
582 SoURLLoader(URLClassLoader classloader, URL url, URL overrideURL)
584 super(classloader, url, overrideURL);
585 helper = SharedLibHelper.findHelper(classloader, url.getFile(),
586 noCertCodeSource);
589 Class getClass(String className)
591 return helper.findClass(className);
594 Resource getResource(String name)
596 URL url = helper.findResource(name);
597 if (url == null)
598 return null;
599 return new SoResource(this, name, url);
603 final static class SoResource extends Resource
605 SoResource(SoURLLoader loader, String name, URL url)
607 super(loader, name);
608 this.url = url;
611 InputStream getInputStream() throws IOException
613 URLConnection conn = url.openConnection();
614 return conn.getInputStream();
617 public int getLength()
619 // FIXME we could find this by asking the core object.
620 return -1;
623 public URL getURL ()
625 return url;
628 final URL url;
632 * A <code>FileURLLoader</code> is a type of <code>URLLoader</code>
633 * only loading from file url.
635 static final class FileURLLoader extends URLLoader
637 File dir; //the file for this file url
639 FileURLLoader(URLClassLoader classloader, URL url)
641 super(classloader, url);
642 dir = new File(baseURL.getFile());
645 /** get resource with the name "name" in the file url */
646 Resource getResource(String name)
648 File file = new File(dir, name);
649 if (file.exists() && ! file.isDirectory())
650 return new FileResource(this, name, file);
651 return null;
655 static final class FileResource extends Resource
657 final File file;
659 FileResource(FileURLLoader loader, String name, File file)
661 super(loader, name);
662 this.file = file;
665 InputStream getInputStream() throws IOException
667 return new FileInputStream(file);
670 public int getLength()
672 return (int) file.length();
675 public String toString ()
677 return "file " +file.getAbsolutePath();
680 public URL getURL()
684 return new URL(loader.baseURL, name,
685 loader.classloader.getURLStreamHandler("file"));
687 catch (MalformedURLException e)
689 InternalError ie = new InternalError();
690 ie.initCause(e);
691 throw ie;
696 // Constructors
699 * Creates a URLClassLoader that gets classes from the supplied URLs.
700 * To determine if this classloader may be created the constructor of
701 * the super class (<code>SecureClassLoader</code>) is called first, which
702 * can throw a SecurityException. Then the supplied URLs are added
703 * in the order given to the URLClassLoader which uses these URLs to
704 * load classes and resources (after using the default parent ClassLoader).
706 * @exception SecurityException if the SecurityManager disallows the
707 * creation of a ClassLoader.
708 * @param urls Locations that should be searched by this ClassLoader when
709 * resolving Classes or Resources.
710 * @see SecureClassLoader
712 public URLClassLoader(URL[] urls) throws SecurityException
714 super();
715 this.factory = null;
716 this.securityContext = null;
717 addURLs(urls);
721 * Private constructor used by the static
722 * <code>newInstance(URL[])</code> method. Creates an
723 * <code>URLClassLoader</code> without any <code>URL</code>s
724 * yet. This is used to bypass the normal security check for
725 * creating classloaders, but remembers the security context which
726 * will be used when defining classes. The <code>URL</code>s to
727 * load from must be added by the <code>newInstance()</code> method
728 * in the security context of the caller.
730 * @param securityContext the security context of the unprivileged code.
732 private URLClassLoader(AccessControlContext securityContext)
734 super();
735 this.factory = null;
736 this.securityContext = securityContext;
740 * Creates a <code>URLClassLoader</code> that gets classes from the supplied
741 * <code>URL</code>s.
742 * To determine if this classloader may be created the constructor of
743 * the super class (<code>SecureClassLoader</code>) is called first, which
744 * can throw a SecurityException. Then the supplied URLs are added
745 * in the order given to the URLClassLoader which uses these URLs to
746 * load classes and resources (after using the supplied parent ClassLoader).
747 * @exception SecurityException if the SecurityManager disallows the
748 * creation of a ClassLoader.
749 * @exception SecurityException
750 * @param urls Locations that should be searched by this ClassLoader when
751 * resolving Classes or Resources.
752 * @param parent The parent class loader used before trying this class
753 * loader.
754 * @see SecureClassLoader
756 public URLClassLoader(URL[] urls, ClassLoader parent)
757 throws SecurityException
759 super(parent);
760 this.factory = null;
761 this.securityContext = null;
762 addURLs(urls);
765 // Package-private to avoid a trampoline constructor.
767 * Package-private constructor used by the static
768 * <code>newInstance(URL[])</code> method. Creates an
769 * <code>URLClassLoader</code> with the given parent but without any
770 * <code>URL</code>s yet. This is used to bypass the normal security
771 * check for creating classloaders, but remembers the security
772 * context which will be used when defining classes. The
773 * <code>URL</code>s to load from must be added by the
774 * <code>newInstance()</code> method in the security context of the
775 * caller.
777 * @param securityContext the security context of the unprivileged code.
779 URLClassLoader(ClassLoader parent, AccessControlContext securityContext)
781 super(parent);
782 this.factory = null;
783 this.securityContext = securityContext;
787 * Creates a URLClassLoader that gets classes from the supplied URLs.
788 * To determine if this classloader may be created the constructor of
789 * the super class (<CODE>SecureClassLoader</CODE>) is called first, which
790 * can throw a SecurityException. Then the supplied URLs are added
791 * in the order given to the URLClassLoader which uses these URLs to
792 * load classes and resources (after using the supplied parent ClassLoader).
793 * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the
794 * protocol handlers of the supplied URLs.
795 * @exception SecurityException if the SecurityManager disallows the
796 * creation of a ClassLoader.
797 * @exception SecurityException
798 * @param urls Locations that should be searched by this ClassLoader when
799 * resolving Classes or Resources.
800 * @param parent The parent class loader used before trying this class
801 * loader.
802 * @param factory Used to get the protocol handler for the URLs.
803 * @see SecureClassLoader
805 public URLClassLoader(URL[] urls, ClassLoader parent,
806 URLStreamHandlerFactory factory)
807 throws SecurityException
809 super(parent);
810 this.securityContext = null;
811 this.factory = factory;
812 addURLs(urls);
814 // If this factory is still not in factoryCache, add it,
815 // since we only support three protocols so far, 5 is enough
816 // for cache initial size
817 synchronized (factoryCache)
819 if (factory != null && factoryCache.get(factory) == null)
820 factoryCache.put(factory, new HashMap(5));
824 // Methods
827 * Adds a new location to the end of the internal URL store.
828 * @param newUrl the location to add
830 protected void addURL(URL newUrl)
832 urls.add(newUrl);
833 addURLImpl(newUrl);
836 private void addURLImpl(URL newUrl)
838 synchronized (urlloaders)
840 if (newUrl == null)
841 return; // Silently ignore...
843 // Check global cache to see if there're already url loader
844 // for this url.
845 URLLoader loader = (URLLoader) urlloaders.get(newUrl);
846 if (loader == null)
848 String file = newUrl.getFile();
849 String protocol = newUrl.getProtocol();
851 // Check that it is not a directory
852 if ("gcjlib".equals(protocol))
853 loader = new SoURLLoader(this, newUrl);
854 else if (! (file.endsWith("/") || file.endsWith(File.separator)))
855 loader = new JarURLLoader(this, newUrl);
856 else if ("file".equals(protocol))
857 loader = new FileURLLoader(this, newUrl);
858 else
859 loader = new RemoteURLLoader(this, newUrl);
861 // Cache it.
862 urlloaders.put(newUrl, loader);
865 urlinfos.add(loader);
867 Vector extraUrls = loader.getClassPath();
868 if (extraUrls != null)
870 Iterator it = extraUrls.iterator();
871 while (it.hasNext())
873 URL url = (URL)it.next();
874 URLLoader extraLoader = (URLLoader) urlloaders.get(url);
875 if (! urlinfos.contains (extraLoader))
876 addURLImpl(url);
884 * Adds an array of new locations to the end of the internal URL store.
885 * @param newUrls the locations to add
887 private void addURLs(URL[] newUrls)
889 for (int i = 0; i < newUrls.length; i++)
890 addURL(newUrls[i]);
894 * Defines a Package based on the given name and the supplied manifest
895 * information. The manifest indicates the tile, version and
896 * vendor information of the specification and implementation and wheter the
897 * package is sealed. If the Manifest indicates that the package is sealed
898 * then the Package will be sealed with respect to the supplied URL.
900 * @exception IllegalArgumentException If this package name already exists
901 * in this class loader
902 * @param name The name of the package
903 * @param manifest The manifest describing the specification,
904 * implementation and sealing details of the package
905 * @param url the code source url to seal the package
906 * @return the defined Package
908 protected Package definePackage(String name, Manifest manifest, URL url)
909 throws IllegalArgumentException
911 Attributes attr = manifest.getMainAttributes();
912 String specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
913 String specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
914 String specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
915 String implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
916 String implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
917 String implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
919 // Look if the Manifest indicates that this package is sealed
920 // XXX - most likely not completely correct!
921 // Shouldn't we also check the sealed attribute of the complete jar?
922 // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled
923 // But how do we get that jar manifest here?
924 String sealed = attr.getValue(Attributes.Name.SEALED);
925 if ("false".equals(sealed))
926 // make sure that the URL is null so the package is not sealed
927 url = null;
929 return definePackage(name, specTitle, specVersion, specVendor, implTitle,
930 implVersion, implVendor, url);
934 * Finds (the first) class by name from one of the locations. The locations
935 * are searched in the order they were added to the URLClassLoader.
937 * @param className the classname to find
938 * @exception ClassNotFoundException when the class could not be found or
939 * loaded
940 * @return a Class object representing the found class
942 protected Class findClass(final String className)
943 throws ClassNotFoundException
945 // Just try to find the resource by the (almost) same name
946 String resourceName = className.replace('.', '/') + ".class";
947 int max = urlinfos.size();
948 Resource resource = null;
949 for (int i = 0; i < max && resource == null; i++)
951 URLLoader loader = (URLLoader)urlinfos.elementAt(i);
952 if (loader == null)
953 continue;
955 Class k = loader.getClass(className);
956 if (k != null)
957 return k;
959 resource = loader.getResource(resourceName);
961 if (resource == null)
962 throw new ClassNotFoundException(className + " not found in " + this);
964 // Try to read the class data, create the CodeSource, Package and
965 // construct the class (and watch out for those nasty IOExceptions)
968 byte[] data;
969 InputStream in = resource.getInputStream();
970 int length = resource.getLength();
971 if (length != -1)
973 // We know the length of the data.
974 // Just try to read it in all at once
975 data = new byte[length];
976 int pos = 0;
977 while (length - pos > 0)
979 int len = in.read(data, pos, length - pos);
980 if (len == -1)
981 throw new EOFException("Not enough data reading from: "
982 + in);
983 pos += len;
986 else
988 // We don't know the data length.
989 // Have to read it in chunks.
990 ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
991 byte[] b = new byte[4096];
992 int l = 0;
993 while (l != -1)
995 l = in.read(b);
996 if (l != -1)
997 out.write(b, 0, l);
999 data = out.toByteArray();
1001 final byte[] classData = data;
1003 // Now get the CodeSource
1004 final CodeSource source = resource.getCodeSource();
1006 // Find out package name
1007 String packageName = null;
1008 int lastDot = className.lastIndexOf('.');
1009 if (lastDot != -1)
1010 packageName = className.substring(0, lastDot);
1012 if (packageName != null && getPackage(packageName) == null)
1014 // define the package
1015 Manifest manifest = resource.loader.getManifest();
1016 if (manifest == null)
1017 definePackage(packageName, null, null, null, null, null, null,
1018 null);
1019 else
1020 definePackage(packageName, manifest, resource.loader.baseURL);
1023 // And finally construct the class!
1024 SecurityManager sm = System.getSecurityManager();
1025 if (sm != null && securityContext != null)
1027 return (Class)AccessController.doPrivileged
1028 (new PrivilegedAction()
1030 public Object run()
1032 return defineClass(className, classData,
1033 0, classData.length,
1034 source);
1036 }, securityContext);
1038 else
1039 return defineClass(className, classData, 0, classData.length, source);
1041 catch (IOException ioe)
1043 ClassNotFoundException cnfe;
1044 cnfe = new ClassNotFoundException(className + " not found in " + this);
1045 cnfe.initCause(ioe);
1046 throw cnfe;
1050 // Cached String representation of this URLClassLoader
1051 private String thisString;
1054 * Returns a String representation of this URLClassLoader giving the
1055 * actual Class name, the URLs that are searched and the parent
1056 * ClassLoader.
1058 public String toString()
1060 if (thisString == null)
1062 StringBuffer sb = new StringBuffer();
1063 sb.append(this.getClass().getName());
1064 sb.append("{urls=[" );
1065 URL[] thisURLs = getURLs();
1066 for (int i = 0; i < thisURLs.length; i++)
1068 sb.append(thisURLs[i]);
1069 if (i < thisURLs.length - 1)
1070 sb.append(',');
1072 sb.append(']');
1073 sb.append(", parent=");
1074 sb.append(getParent());
1075 sb.append('}');
1076 thisString = sb.toString();
1078 return thisString;
1082 * Finds the first occurrence of a resource that can be found. The locations
1083 * are searched in the order they were added to the URLClassLoader.
1085 * @param resourceName the resource name to look for
1086 * @return the URLResource for the resource if found, null otherwise
1088 private Resource findURLResource(String resourceName)
1090 int max = urlinfos.size();
1091 for (int i = 0; i < max; i++)
1093 URLLoader loader = (URLLoader) urlinfos.elementAt(i);
1094 if (loader == null)
1095 continue;
1097 Resource resource = loader.getResource(resourceName);
1098 if (resource != null)
1099 return resource;
1101 return null;
1105 * Finds the first occurrence of a resource that can be found.
1107 * @param resourceName the resource name to look for
1108 * @return the URL if found, null otherwise
1110 public URL findResource(String resourceName)
1112 Resource resource = findURLResource(resourceName);
1113 if (resource != null)
1114 return resource.getURL();
1116 // Resource not found
1117 return null;
1121 * If the URLStreamHandlerFactory has been set this return the appropriate
1122 * URLStreamHandler for the given protocol, if not set returns null.
1124 * @param protocol the protocol for which we need a URLStreamHandler
1125 * @return the appropriate URLStreamHandler or null
1127 URLStreamHandler getURLStreamHandler(String protocol)
1129 if (factory == null)
1130 return null;
1132 URLStreamHandler handler;
1133 synchronized (factoryCache)
1135 // Check if there're handler for the same protocol in cache.
1136 HashMap cache = (HashMap) factoryCache.get(factory);
1137 handler = (URLStreamHandler) cache.get(protocol);
1138 if (handler == null)
1140 // Add it to cache.
1141 handler = factory.createURLStreamHandler(protocol);
1142 cache.put(protocol, handler);
1145 return handler;
1149 * Finds all the resources with a particular name from all the locations.
1151 * @exception IOException when an error occurs accessing one of the
1152 * locations
1153 * @param resourceName the name of the resource to lookup
1154 * @return a (possible empty) enumeration of URLs where the resource can be
1155 * found
1157 public Enumeration findResources(String resourceName)
1158 throws IOException
1160 Vector resources = new Vector();
1161 int max = urlinfos.size();
1162 for (int i = 0; i < max; i++)
1164 URLLoader loader = (URLLoader) urlinfos.elementAt(i);
1165 Resource resource = loader.getResource(resourceName);
1166 if (resource != null)
1167 resources.add(resource.getURL());
1169 return resources.elements();
1173 * Returns the permissions needed to access a particular code
1174 * source. These permissions includes those returned by
1175 * <code>SecureClassLoader.getPermissions()</code> and the actual
1176 * permissions to access the objects referenced by the URL of the
1177 * code source. The extra permissions added depend on the protocol
1178 * and file portion of the URL in the code source. If the URL has
1179 * the "file" protocol ends with a '/' character then it must be a
1180 * directory and a file Permission to read everything in that
1181 * directory and all subdirectories is added. If the URL had the
1182 * "file" protocol and doesn't end with a '/' character then it must
1183 * be a normal file and a file permission to read that file is
1184 * added. If the <code>URL</code> has any other protocol then a
1185 * socket permission to connect and accept connections from the host
1186 * portion of the URL is added.
1188 * @param source The codesource that needs the permissions to be accessed
1189 * @return the collection of permissions needed to access the code resource
1190 * @see java.security.SecureClassLoader#getPermissions()
1192 protected PermissionCollection getPermissions(CodeSource source)
1194 // XXX - This implementation does exactly as the Javadoc describes.
1195 // But maybe we should/could use URLConnection.getPermissions()?
1196 // First get the permissions that would normally be granted
1197 PermissionCollection permissions = super.getPermissions(source);
1199 // Now add any extra permissions depending on the URL location.
1200 URL url = source.getLocation();
1201 String protocol = url.getProtocol();
1202 if (protocol.equals("file"))
1204 String file = url.getFile();
1206 // If the file end in / it must be an directory.
1207 if (file.endsWith("/") || file.endsWith(File.separator))
1209 // Grant permission to read everything in that directory and
1210 // all subdirectories.
1211 permissions.add(new FilePermission(file + "-", "read"));
1213 else
1215 // It is a 'normal' file.
1216 // Grant permission to access that file.
1217 permissions.add(new FilePermission(file, "read"));
1220 else
1222 // Grant permission to connect to and accept connections from host
1223 String host = url.getHost();
1224 if (host != null)
1225 permissions.add(new SocketPermission(host, "connect,accept"));
1228 return permissions;
1232 * Returns all the locations that this class loader currently uses the
1233 * resolve classes and resource. This includes both the initially supplied
1234 * URLs as any URLs added later by the loader.
1235 * @return All the currently used URLs
1237 public URL[] getURLs()
1239 return (URL[]) urls.toArray(new URL[urls.size()]);
1243 * Creates a new instance of a <code>URLClassLoader</code> that gets
1244 * classes from the supplied <code>URL</code>s. This class loader
1245 * will have as parent the standard system class loader.
1247 * @param urls the initial URLs used to resolve classes and
1248 * resources
1250 * @return the class loader
1252 * @exception SecurityException when the calling code does not have
1253 * permission to access the given <code>URL</code>s
1255 public static URLClassLoader newInstance(URL[] urls)
1256 throws SecurityException
1258 return newInstance(urls, null);
1262 * Creates a new instance of a <code>URLClassLoader</code> that gets
1263 * classes from the supplied <code>URL</code>s and with the supplied
1264 * loader as parent class loader.
1266 * @param urls the initial URLs used to resolve classes and
1267 * resources
1268 * @param parent the parent class loader
1270 * @return the class loader
1272 * @exception SecurityException when the calling code does not have
1273 * permission to access the given <code>URL</code>s
1275 public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent)
1276 throws SecurityException
1278 SecurityManager sm = System.getSecurityManager();
1279 if (sm == null)
1280 return new URLClassLoader(urls, parent);
1281 else
1283 final Object securityContext = sm.getSecurityContext();
1285 // XXX - What to do with anything else then an AccessControlContext?
1286 if (! (securityContext instanceof AccessControlContext))
1287 throw new SecurityException("securityContext must be AccessControlContext: "
1288 + securityContext);
1290 URLClassLoader loader =
1291 (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction()
1293 public Object run()
1295 return new URLClassLoader(parent,
1296 (AccessControlContext) securityContext);
1299 loader.addURLs(urls);
1300 return loader;