Merged gcj-eclipse branch to trunk.
[official-gcc.git] / libjava / java / net / URLClassLoader.java
blobfd70fdf2045a8dcbcb157d344cbb6e787933480d
1 /* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
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., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 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;
66 import gnu.gcj.Core;
67 import gnu.java.net.protocol.core.CoreInputStream;
69 /**
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>
100 * <p>Open issues:
101 * <ul>
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
110 * precisely?</li>
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
114 * places?</li>
116 * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li>
118 * </ul>
119 * </p>
121 * @since 1.2
123 * @author Mark Wielaard (mark@klomp.org)
124 * @author Wu Gansha (gansha.wu@intel.com)
126 public class URLClassLoader extends SecureClassLoader
128 // Class Variables
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
133 * comes.
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;
168 // Helper classes
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.
184 final URL baseURL;
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
211 * at all.
213 Class getClass(String className)
215 return null;
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()
232 return null;
235 Vector getClassPath()
237 return null;
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;
252 Resource(URLLoader loader)
254 this.loader = loader;
258 * Returns the non-null <code>CodeSource</code> associated with
259 * this resource.
261 CodeSource getCodeSource()
263 Certificate[] certs = getCertificates();
264 if (certs == null)
265 return loader.noCertCodeSource;
266 else
267 return new CodeSource(loader.baseURL, certs);
271 * Returns <code>Certificates</code> associated with this
272 * resource, or null when there are none.
274 Certificate[] getCertificates()
276 return null;
280 * Return a <code>URL</code> that can be used to access this resource.
282 abstract URL getURL();
285 * Returns the size of this <code>Resource</code> in bytes or
286 * <code>-1</code> when unknown.
288 abstract int getLength();
291 * Returns the non-null <code>InputStream</code> through which
292 * this resource can be loaded.
294 abstract InputStream getInputStream() throws IOException;
298 * A <code>JarURLLoader</code> is a type of <code>URLLoader</code>
299 * only loading from jar url.
301 static final class JarURLLoader extends URLLoader
303 final JarFile jarfile; // The jar file for this url
304 final URL baseJarURL; // Base jar: url for all resources loaded from jar
306 Vector classPath; // The "Class-Path" attribute of this Jar's manifest
308 public JarURLLoader(URLClassLoader classloader, URL baseURL,
309 URL absoluteUrl)
311 super(classloader, baseURL, absoluteUrl);
313 // Cache url prefix for all resources in this jar url.
314 String external = baseURL.toExternalForm();
315 StringBuffer sb = new StringBuffer(external.length() + 6);
316 sb.append("jar:");
317 sb.append(external);
318 sb.append("!/");
319 String jarURL = sb.toString();
321 this.classPath = null;
322 URL baseJarURL = null;
323 JarFile jarfile = null;
326 baseJarURL =
327 new URL(null, jarURL, classloader.getURLStreamHandler("jar"));
329 jarfile =
330 ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
332 Manifest manifest;
333 Attributes attributes;
334 String classPathString;
336 if ((manifest = jarfile.getManifest()) != null
337 && (attributes = manifest.getMainAttributes()) != null
338 && ((classPathString
339 = attributes.getValue(Attributes.Name.CLASS_PATH))
340 != null))
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)
355 // Give up
360 catch (IOException ioe)
362 /* ignored */
365 this.baseJarURL = baseJarURL;
366 this.jarfile = jarfile;
369 /** get resource with the name "name" in the jar url */
370 Resource getResource(String name)
372 if (jarfile == null)
373 return null;
375 if (name.startsWith("/"))
376 name = name.substring(1);
378 JarEntry je = jarfile.getJarEntry(name);
379 if (je != null)
380 return new JarURLResource(this, name, je);
381 else
382 return null;
385 Manifest getManifest()
389 return (jarfile == null) ? null : jarfile.getManifest();
391 catch (IOException ioe)
393 return null;
397 Vector getClassPath()
399 return classPath;
403 static final class JarURLResource extends Resource
405 private final JarEntry entry;
406 private final String name;
408 JarURLResource(JarURLLoader loader, String name, JarEntry entry)
410 super(loader);
411 this.entry = entry;
412 this.name = name;
415 InputStream getInputStream() throws IOException
417 return ((JarURLLoader) loader).jarfile.getInputStream(entry);
420 int getLength()
422 return (int) entry.getSize();
425 Certificate[] getCertificates()
427 // We have to get the entry from the jar file again, because the
428 // certificates will not be available until the entire entry has
429 // been read.
430 return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name))
431 .getCertificates();
434 URL getURL()
438 return new URL(((JarURLLoader) loader).baseJarURL, name,
439 loader.classloader.getURLStreamHandler("jar"));
441 catch (MalformedURLException e)
443 InternalError ie = new InternalError();
444 ie.initCause(e);
445 throw ie;
451 * Loader for remote directories.
453 static final class RemoteURLLoader extends URLLoader
455 private final String protocol;
457 RemoteURLLoader(URLClassLoader classloader, URL url)
459 super(classloader, url);
460 protocol = url.getProtocol();
464 * Get a remote resource.
465 * Returns null if no such resource exists.
467 Resource getResource(String name)
471 URL url =
472 new URL(baseURL, name, classloader.getURLStreamHandler(protocol));
473 URLConnection connection = url.openConnection();
475 // Open the connection and check the stream
476 // just to be sure it exists.
477 int length = connection.getContentLength();
478 InputStream stream = connection.getInputStream();
480 // We can do some extra checking if it is a http request
481 if (connection instanceof HttpURLConnection)
483 int response =
484 ((HttpURLConnection) connection).getResponseCode();
485 if (response / 100 != 2)
486 return null;
489 if (stream != null)
490 return new RemoteResource(this, name, url, stream, length);
491 else
492 return null;
494 catch (IOException ioe)
496 return null;
502 * A resource from some remote location.
504 static final class RemoteResource extends Resource
506 private final URL url;
507 private final InputStream stream;
508 private final int length;
510 RemoteResource(RemoteURLLoader loader, String name, URL url,
511 InputStream stream, int length)
513 super(loader);
514 this.url = url;
515 this.stream = stream;
516 this.length = length;
519 InputStream getInputStream() throws IOException
521 return stream;
524 public int getLength()
526 return length;
529 public URL getURL()
531 return url;
536 * A <code>SoURLLoader</code> is a type of <code>URLLoader</code>
537 * that loads classes and resources from a shared library.
539 final static class SoURLLoader extends URLLoader
541 SharedLibHelper helper;
543 SoURLLoader(URLClassLoader classloader, URL url)
545 this(classloader, url, url);
548 SoURLLoader(URLClassLoader classloader, URL url, URL overrideURL)
550 super(classloader, url, overrideURL);
551 helper = SharedLibHelper.findHelper(classloader, url.getFile(),
552 noCertCodeSource, true);
555 Class getClass(String className)
557 return helper.findClass(className);
560 Resource getResource(String name)
562 URL url = helper.findResource(name);
563 if (url == null)
564 return null;
565 return new SoResource(this, url);
569 final static class SoResource extends Resource
571 SoResource(SoURLLoader loader, URL url)
573 super(loader);
574 this.url = url;
577 InputStream getInputStream() throws IOException
579 URLConnection conn = url.openConnection();
580 return conn.getInputStream();
583 public int getLength()
585 // FIXME we could find this by asking the core object.
586 return -1;
589 public URL getURL ()
591 return url;
594 final URL url;
598 * A <code>FileURLLoader</code> is a type of <code>URLLoader</code>
599 * only loading from file url.
601 static final class FileURLLoader extends URLLoader
603 File dir; //the file for this file url
605 FileURLLoader(URLClassLoader classloader, URL url, URL absoluteUrl)
607 super(classloader, url, absoluteUrl);
608 dir = new File(absoluteUrl.getFile());
611 /** get resource with the name "name" in the file url */
612 Resource getResource(String name)
614 try
616 File file = new File(dir, name).getCanonicalFile();
617 if (file.exists() && !file.isDirectory())
618 return new FileResource(this, file);
620 catch (IOException e)
622 // Fall through...
624 return null;
628 static final class FileResource extends Resource
630 final File file;
632 FileResource(FileURLLoader loader, File file)
634 super(loader);
635 this.file = file;
638 InputStream getInputStream() throws IOException
640 // Delegate to the URL content handler mechanism to retrieve an
641 // HTML representation of the directory listing if a directory
642 if (file.isDirectory())
644 URL url = getURL();
645 return url.openStream();
647 // Otherwise simply return a FileInputStream
648 return new FileInputStream(file);
651 public int getLength()
653 // Delegate to the URL content handler mechanism to retrieve the
654 // length of the HTML representation of the directory listing if
655 // a directory, or -1 if an exception occurs opening the directory.
656 if (file.isDirectory())
658 URL url = getURL();
661 URLConnection connection = url.openConnection();
662 return connection.getContentLength();
664 catch (IOException e)
666 return -1;
669 // Otherwise simply return the file length
670 return (int) file.length();
673 public URL getURL()
677 return file.toURL();
679 catch (MalformedURLException e)
681 InternalError ie = new InternalError();
682 ie.initCause(e);
683 throw ie;
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
694 private String dir;
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);
706 if (core != null)
707 return new CoreResource(this, name, core);
708 return null;
712 static final class CoreResource extends Resource
714 private final Core core;
715 private final String name;
717 CoreResource(CoreURLLoader loader, String name, Core core)
719 super(loader);
720 this.core = core;
721 this.name = name;
724 InputStream getInputStream() throws IOException
726 return new CoreInputStream(core);
729 public int getLength()
731 return core.length;
734 public URL getURL()
738 return new URL(loader.baseURL, name,
739 loader.classloader.getURLStreamHandler("core"));
741 catch (MalformedURLException e)
743 InternalError ie = new InternalError();
744 ie.initCause(e);
745 throw ie;
750 // Constructors
753 * Creates a URLClassLoader that gets classes from the supplied URLs.
754 * To determine if this classloader may be created the constructor of
755 * the super class (<code>SecureClassLoader</code>) is called first, which
756 * can throw a SecurityException. Then the supplied URLs are added
757 * in the order given to the URLClassLoader which uses these URLs to
758 * load classes and resources (after using the default parent ClassLoader).
760 * @param urls Locations that should be searched by this ClassLoader when
761 * resolving Classes or Resources.
762 * @exception SecurityException if the SecurityManager disallows the
763 * creation of a ClassLoader.
764 * @see SecureClassLoader
766 public URLClassLoader(URL[] urls) throws SecurityException
768 super();
769 this.factory = null;
770 this.securityContext = null;
771 addURLs(urls);
775 * Creates a <code>URLClassLoader</code> that gets classes from the supplied
776 * <code>URL</code>s.
777 * To determine if this classloader may be created the constructor of
778 * the super class (<code>SecureClassLoader</code>) is called first, which
779 * can throw a SecurityException. Then the supplied URLs are added
780 * in the order given to the URLClassLoader which uses these URLs to
781 * load classes and resources (after using the supplied parent ClassLoader).
782 * @param urls Locations that should be searched by this ClassLoader when
783 * resolving Classes or Resources.
784 * @param parent The parent class loader used before trying this class
785 * loader.
786 * @exception SecurityException if the SecurityManager disallows the
787 * creation of a ClassLoader.
788 * @exception SecurityException
789 * @see SecureClassLoader
791 public URLClassLoader(URL[] urls, ClassLoader parent)
792 throws SecurityException
794 super(parent);
795 this.factory = null;
796 this.securityContext = null;
797 addURLs(urls);
800 // Package-private to avoid a trampoline constructor.
802 * Package-private constructor used by the static
803 * <code>newInstance(URL[])</code> method. Creates an
804 * <code>URLClassLoader</code> with the given parent but without any
805 * <code>URL</code>s yet. This is used to bypass the normal security
806 * check for creating classloaders, but remembers the security
807 * context which will be used when defining classes. The
808 * <code>URL</code>s to load from must be added by the
809 * <code>newInstance()</code> method in the security context of the
810 * caller.
812 * @param securityContext the security context of the unprivileged code.
814 URLClassLoader(ClassLoader parent, AccessControlContext securityContext)
816 super(parent);
817 this.factory = null;
818 this.securityContext = securityContext;
822 * Creates a URLClassLoader that gets classes from the supplied URLs.
823 * To determine if this classloader may be created the constructor of
824 * the super class (<CODE>SecureClassLoader</CODE>) is called first, which
825 * can throw a SecurityException. Then the supplied URLs are added
826 * in the order given to the URLClassLoader which uses these URLs to
827 * load classes and resources (after using the supplied parent ClassLoader).
828 * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the
829 * protocol handlers of the supplied URLs.
830 * @param urls Locations that should be searched by this ClassLoader when
831 * resolving Classes or Resources.
832 * @param parent The parent class loader used before trying this class
833 * loader.
834 * @param factory Used to get the protocol handler for the URLs.
835 * @exception SecurityException if the SecurityManager disallows the
836 * creation of a ClassLoader.
837 * @exception SecurityException
838 * @see SecureClassLoader
840 public URLClassLoader(URL[] urls, ClassLoader parent,
841 URLStreamHandlerFactory factory)
842 throws SecurityException
844 super(parent);
845 this.securityContext = null;
846 this.factory = factory;
847 addURLs(urls);
849 // If this factory is still not in factoryCache, add it,
850 // since we only support three protocols so far, 5 is enough
851 // for cache initial size
852 synchronized (factoryCache)
854 if (factory != null && factoryCache.get(factory) == null)
855 factoryCache.put(factory, new HashMap(5));
859 // Methods
862 * Adds a new location to the end of the internal URL store.
863 * @param newUrl the location to add
865 protected void addURL(URL newUrl)
867 urls.add(newUrl);
868 addURLImpl(newUrl);
871 private void addURLImpl(URL newUrl)
873 synchronized (this)
875 if (newUrl == null)
876 return; // Silently ignore...
878 // Reset the toString() value.
879 thisString = null;
881 // Check global cache to see if there're already url loader
882 // for this url.
883 URLLoader loader = (URLLoader) urlloaders.get(newUrl);
884 if (loader == null)
886 String file = newUrl.getFile();
887 String protocol = newUrl.getProtocol();
889 // If we have a file: URL, we want to make it absolute
890 // here, before we decide whether it is really a jar.
891 URL absoluteURL;
892 if ("file".equals (protocol))
894 File dir = new File(file);
895 URL absUrl;
898 absoluteURL = dir.getCanonicalFile().toURL();
900 catch (IOException ignore)
904 absoluteURL = dir.getAbsoluteFile().toURL();
906 catch (MalformedURLException _)
908 // This really should not happen.
909 absoluteURL = newUrl;
913 else
915 // This doesn't hurt, and it simplifies the logic a
916 // little.
917 absoluteURL = newUrl;
920 // Check that it is not a directory
921 if ("gcjlib".equals(protocol))
922 loader = new SoURLLoader(this, newUrl);
923 else if (! (file.endsWith("/") || file.endsWith(File.separator)))
924 loader = new JarURLLoader(this, newUrl, absoluteURL);
925 else if ("file".equals(protocol))
926 loader = new FileURLLoader(this, newUrl, absoluteURL);
927 else if ("core".equals(protocol))
928 loader = new CoreURLLoader(this, newUrl);
929 else
930 loader = new RemoteURLLoader(this, newUrl);
932 // Cache it.
933 urlloaders.put(newUrl, loader);
936 urlinfos.add(loader);
938 Vector extraUrls = loader.getClassPath();
939 if (extraUrls != null)
941 Iterator it = extraUrls.iterator();
942 while (it.hasNext())
944 URL url = (URL)it.next();
945 URLLoader extraLoader = (URLLoader) urlloaders.get(url);
946 if (! urlinfos.contains (extraLoader))
947 addURLImpl(url);
955 * Adds an array of new locations to the end of the internal URL
956 * store. Called from the the constructors. Should not call to the
957 * protected addURL() method since that can be overridden and
958 * subclasses are not yet in a good state at this point.
959 * jboss 4.0.3 for example depends on this.
961 * @param newUrls the locations to add
963 private void addURLs(URL[] newUrls)
965 for (int i = 0; i < newUrls.length; i++)
967 urls.add(newUrls[i]);
968 addURLImpl(newUrls[i]);
973 * Look in both Attributes for a given value. The first Attributes
974 * object, if not null, has precedence.
976 private String getAttributeValue(Attributes.Name name, Attributes first,
977 Attributes second)
979 String result = null;
980 if (first != null)
981 result = first.getValue(name);
982 if (result == null)
983 result = second.getValue(name);
984 return result;
988 * Defines a Package based on the given name and the supplied manifest
989 * information. The manifest indicates the title, version and
990 * vendor information of the specification and implementation and whether the
991 * package is sealed. If the Manifest indicates that the package is sealed
992 * then the Package will be sealed with respect to the supplied URL.
994 * @param name The name of the package
995 * @param manifest The manifest describing the specification,
996 * implementation and sealing details of the package
997 * @param url the code source url to seal the package
998 * @return the defined Package
999 * @throws IllegalArgumentException If this package name already exists
1000 * in this class loader
1002 protected Package definePackage(String name, Manifest manifest, URL url)
1003 throws IllegalArgumentException
1005 // Compute the name of the package as it may appear in the
1006 // Manifest.
1007 StringBuffer xform = new StringBuffer(name);
1008 for (int i = xform.length () - 1; i >= 0; --i)
1009 if (xform.charAt(i) == '.')
1010 xform.setCharAt(i, '/');
1011 xform.append('/');
1012 String xformName = xform.toString();
1014 Attributes entryAttr = manifest.getAttributes(xformName);
1015 Attributes attr = manifest.getMainAttributes();
1017 String specTitle
1018 = getAttributeValue(Attributes.Name.SPECIFICATION_TITLE,
1019 entryAttr, attr);
1020 String specVersion
1021 = getAttributeValue(Attributes.Name.SPECIFICATION_VERSION,
1022 entryAttr, attr);
1023 String specVendor
1024 = getAttributeValue(Attributes.Name.SPECIFICATION_VENDOR,
1025 entryAttr, attr);
1026 String implTitle
1027 = getAttributeValue(Attributes.Name.IMPLEMENTATION_TITLE,
1028 entryAttr, attr);
1029 String implVersion
1030 = getAttributeValue(Attributes.Name.IMPLEMENTATION_VERSION,
1031 entryAttr, attr);
1032 String implVendor
1033 = getAttributeValue(Attributes.Name.IMPLEMENTATION_VENDOR,
1034 entryAttr, attr);
1036 // Look if the Manifest indicates that this package is sealed
1037 // XXX - most likely not completely correct!
1038 // Shouldn't we also check the sealed attribute of the complete jar?
1039 // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled
1040 // But how do we get that jar manifest here?
1041 String sealed = attr.getValue(Attributes.Name.SEALED);
1042 if ("false".equals(sealed))
1043 // make sure that the URL is null so the package is not sealed
1044 url = null;
1046 return definePackage(name,
1047 specTitle, specVendor, specVersion,
1048 implTitle, implVendor, implVersion,
1049 url);
1053 * Finds (the first) class by name from one of the locations. The locations
1054 * are searched in the order they were added to the URLClassLoader.
1056 * @param className the classname to find
1057 * @exception ClassNotFoundException when the class could not be found or
1058 * loaded
1059 * @return a Class object representing the found class
1061 protected Class findClass(final String className)
1062 throws ClassNotFoundException
1064 // Just try to find the resource by the (almost) same name
1065 String resourceName = className.replace('.', '/') + ".class";
1066 int max = urlinfos.size();
1067 Resource resource = null;
1068 for (int i = 0; i < max && resource == null; i++)
1070 URLLoader loader = (URLLoader)urlinfos.elementAt(i);
1071 if (loader == null)
1072 continue;
1074 Class k = loader.getClass(className);
1075 if (k != null)
1076 return k;
1078 resource = loader.getResource(resourceName);
1080 if (resource == null)
1082 String message = className + " not found";
1083 // Calling this.toString() during VM startup when a
1084 // security manager is in force causes the stack to
1085 // be unwound before it can properly be decoded.
1086 if (Thread.currentThread() != null)
1087 message += " in " + this;
1088 throw new ClassNotFoundException(message);
1091 // Try to read the class data, create the CodeSource, Package and
1092 // construct the class (and watch out for those nasty IOExceptions)
1095 byte[] data;
1096 InputStream in = resource.getInputStream();
1099 int length = resource.getLength();
1100 if (length != -1)
1102 // We know the length of the data.
1103 // Just try to read it in all at once
1104 data = new byte[length];
1105 int pos = 0;
1106 while (length - pos > 0)
1108 int len = in.read(data, pos, length - pos);
1109 if (len == -1)
1110 throw new EOFException("Not enough data reading from: "
1111 + in);
1112 pos += len;
1115 else
1117 // We don't know the data length.
1118 // Have to read it in chunks.
1119 ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
1120 byte[] b = new byte[4096];
1121 int l = 0;
1122 while (l != -1)
1124 l = in.read(b);
1125 if (l != -1)
1126 out.write(b, 0, l);
1128 data = out.toByteArray();
1131 finally
1133 in.close();
1135 final byte[] classData = data;
1137 // Now get the CodeSource
1138 final CodeSource source = resource.getCodeSource();
1140 // Find out package name
1141 String packageName = null;
1142 int lastDot = className.lastIndexOf('.');
1143 if (lastDot != -1)
1144 packageName = className.substring(0, lastDot);
1146 if (packageName != null && getPackage(packageName) == null)
1148 // define the package
1149 Manifest manifest = resource.loader.getManifest();
1150 if (manifest == null)
1151 definePackage(packageName, null, null, null, null, null, null,
1152 null);
1153 else
1154 definePackage(packageName, manifest, resource.loader.baseURL);
1157 // And finally construct the class!
1158 SecurityManager sm = System.getSecurityManager();
1159 Class result = null;
1160 if (sm != null && securityContext != null)
1162 result = (Class)AccessController.doPrivileged
1163 (new PrivilegedAction()
1165 public Object run()
1167 return defineClass(className, classData,
1168 0, classData.length,
1169 source);
1171 }, securityContext);
1173 else
1174 result = defineClass(className, classData, 0, classData.length, source);
1176 // Avoid NullPointerExceptions.
1177 Certificate[] resourceCertificates = resource.getCertificates();
1178 if(resourceCertificates != null)
1179 super.setSigners(result, resourceCertificates);
1181 return result;
1183 catch (IOException ioe)
1185 ClassNotFoundException cnfe;
1186 cnfe = new ClassNotFoundException(className + " not found in " + this);
1187 cnfe.initCause(ioe);
1188 throw cnfe;
1192 // Cached String representation of this URLClassLoader
1193 private String thisString;
1196 * Returns a String representation of this URLClassLoader giving the
1197 * actual Class name, the URLs that are searched and the parent
1198 * ClassLoader.
1200 public String toString()
1202 synchronized (this)
1204 if (thisString == null)
1206 StringBuffer sb = new StringBuffer();
1207 sb.append(this.getClass().getName());
1208 sb.append("{urls=[" );
1209 URL[] thisURLs = getURLs();
1210 for (int i = 0; i < thisURLs.length; i++)
1212 sb.append(thisURLs[i]);
1213 if (i < thisURLs.length - 1)
1214 sb.append(',');
1216 sb.append(']');
1217 sb.append(", parent=");
1218 sb.append(getParent());
1219 sb.append('}');
1220 thisString = sb.toString();
1222 return thisString;
1227 * Finds the first occurrence of a resource that can be found. The locations
1228 * are searched in the order they were added to the URLClassLoader.
1230 * @param resourceName the resource name to look for
1231 * @return the URLResource for the resource if found, null otherwise
1233 private Resource findURLResource(String resourceName)
1235 int max = urlinfos.size();
1236 for (int i = 0; i < max; i++)
1238 URLLoader loader = (URLLoader) urlinfos.elementAt(i);
1239 if (loader == null)
1240 continue;
1242 Resource resource = loader.getResource(resourceName);
1243 if (resource != null)
1244 return resource;
1246 return null;
1250 * Finds the first occurrence of a resource that can be found.
1252 * @param resourceName the resource name to look for
1253 * @return the URL if found, null otherwise
1255 public URL findResource(String resourceName)
1257 Resource resource = findURLResource(resourceName);
1258 if (resource != null)
1259 return resource.getURL();
1261 // Resource not found
1262 return null;
1266 * If the URLStreamHandlerFactory has been set this return the appropriate
1267 * URLStreamHandler for the given protocol, if not set returns null.
1269 * @param protocol the protocol for which we need a URLStreamHandler
1270 * @return the appropriate URLStreamHandler or null
1272 URLStreamHandler getURLStreamHandler(String protocol)
1274 if (factory == null)
1275 return null;
1277 URLStreamHandler handler;
1278 synchronized (factoryCache)
1280 // Check if there're handler for the same protocol in cache.
1281 HashMap cache = (HashMap) factoryCache.get(factory);
1282 handler = (URLStreamHandler) cache.get(protocol);
1283 if (handler == null)
1285 // Add it to cache.
1286 handler = factory.createURLStreamHandler(protocol);
1287 cache.put(protocol, handler);
1290 return handler;
1294 * Finds all the resources with a particular name from all the locations.
1296 * @param resourceName the name of the resource to lookup
1297 * @return a (possible empty) enumeration of URLs where the resource can be
1298 * found
1299 * @exception IOException when an error occurs accessing one of the
1300 * locations
1302 public Enumeration findResources(String resourceName)
1303 throws IOException
1305 Vector resources = new Vector();
1306 int max = urlinfos.size();
1307 for (int i = 0; i < max; i++)
1309 URLLoader loader = (URLLoader) urlinfos.elementAt(i);
1310 Resource resource = loader.getResource(resourceName);
1311 if (resource != null)
1312 resources.add(resource.getURL());
1314 return resources.elements();
1318 * Returns the permissions needed to access a particular code
1319 * source. These permissions includes those returned by
1320 * <code>SecureClassLoader.getPermissions()</code> and the actual
1321 * permissions to access the objects referenced by the URL of the
1322 * code source. The extra permissions added depend on the protocol
1323 * and file portion of the URL in the code source. If the URL has
1324 * the "file" protocol ends with a '/' character then it must be a
1325 * directory and a file Permission to read everything in that
1326 * directory and all subdirectories is added. If the URL had the
1327 * "file" protocol and doesn't end with a '/' character then it must
1328 * be a normal file and a file permission to read that file is
1329 * added. If the <code>URL</code> has any other protocol then a
1330 * socket permission to connect and accept connections from the host
1331 * portion of the URL is added.
1333 * @param source The codesource that needs the permissions to be accessed
1334 * @return the collection of permissions needed to access the code resource
1335 * @see java.security.SecureClassLoader#getPermissions(CodeSource)
1337 protected PermissionCollection getPermissions(CodeSource source)
1339 // XXX - This implementation does exactly as the Javadoc describes.
1340 // But maybe we should/could use URLConnection.getPermissions()?
1341 // First get the permissions that would normally be granted
1342 PermissionCollection permissions = super.getPermissions(source);
1344 // Now add any extra permissions depending on the URL location.
1345 URL url = source.getLocation();
1346 String protocol = url.getProtocol();
1347 if (protocol.equals("file"))
1349 String file = url.getFile();
1351 // If the file end in / it must be an directory.
1352 if (file.endsWith("/") || file.endsWith(File.separator))
1354 // Grant permission to read everything in that directory and
1355 // all subdirectories.
1356 permissions.add(new FilePermission(file + "-", "read"));
1358 else
1360 // It is a 'normal' file.
1361 // Grant permission to access that file.
1362 permissions.add(new FilePermission(file, "read"));
1365 else
1367 // Grant permission to connect to and accept connections from host
1368 String host = url.getHost();
1369 if (host != null)
1370 permissions.add(new SocketPermission(host, "connect,accept"));
1373 return permissions;
1377 * Returns all the locations that this class loader currently uses the
1378 * resolve classes and resource. This includes both the initially supplied
1379 * URLs as any URLs added later by the loader.
1380 * @return All the currently used URLs
1382 public URL[] getURLs()
1384 return (URL[]) urls.toArray(new URL[urls.size()]);
1388 * Creates a new instance of a <code>URLClassLoader</code> that gets
1389 * classes from the supplied <code>URL</code>s. This class loader
1390 * will have as parent the standard system class loader.
1392 * @param urls the initial URLs used to resolve classes and
1393 * resources
1395 * @return the class loader
1397 * @exception SecurityException when the calling code does not have
1398 * permission to access the given <code>URL</code>s
1400 public static URLClassLoader newInstance(URL[] urls)
1401 throws SecurityException
1403 return newInstance(urls, null);
1407 * Creates a new instance of a <code>URLClassLoader</code> that gets
1408 * classes from the supplied <code>URL</code>s and with the supplied
1409 * loader as parent class loader.
1411 * @param urls the initial URLs used to resolve classes and
1412 * resources
1413 * @param parent the parent class loader
1415 * @return the class loader
1417 * @exception SecurityException when the calling code does not have
1418 * permission to access the given <code>URL</code>s
1420 public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent)
1421 throws SecurityException
1423 SecurityManager sm = System.getSecurityManager();
1424 if (sm == null)
1425 return new URLClassLoader(urls, parent);
1426 else
1428 final Object securityContext = sm.getSecurityContext();
1430 // XXX - What to do with anything else then an AccessControlContext?
1431 if (! (securityContext instanceof AccessControlContext))
1432 throw new SecurityException("securityContext must be AccessControlContext: "
1433 + securityContext);
1435 URLClassLoader loader =
1436 (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction()
1438 public Object run()
1440 return new URLClassLoader(parent,
1441 (AccessControlContext) securityContext);
1444 loader.addURLs(urls);
1445 return loader;