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)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
42 import java
.io
.ByteArrayOutputStream
;
43 import java
.io
.EOFException
;
45 import java
.io
.FileInputStream
;
46 import java
.io
.FilePermission
;
47 import java
.io
.IOException
;
48 import java
.io
.InputStream
;
49 import java
.security
.AccessControlContext
;
50 import java
.security
.AccessController
;
51 import java
.security
.CodeSource
;
52 import java
.security
.PermissionCollection
;
53 import java
.security
.PrivilegedAction
;
54 import java
.security
.SecureClassLoader
;
55 import java
.security
.cert
.Certificate
;
56 import java
.util
.Enumeration
;
57 import java
.util
.HashMap
;
58 import java
.util
.Iterator
;
59 import java
.util
.StringTokenizer
;
60 import java
.util
.Vector
;
61 import java
.util
.jar
.Attributes
;
62 import java
.util
.jar
.JarEntry
;
63 import java
.util
.jar
.JarFile
;
64 import java
.util
.jar
.Manifest
;
65 import gnu
.gcj
.runtime
.SharedLibHelper
;
67 import gnu
.java
.net
.protocol
.core
.CoreInputStream
;
70 * A secure class loader that can load classes and resources from
71 * multiple locations. Given an array of <code>URL</code>s this class
72 * loader will retrieve classes and resources by fetching them from
73 * possible remote locations. Each <code>URL</code> is searched in
74 * order in which it was added. If the file portion of the
75 * <code>URL</code> ends with a '/' character then it is interpreted
76 * as a base directory, otherwise it is interpreted as a jar file from
77 * which the classes/resources are resolved.
79 * <p>New instances can be created by two static
80 * <code>newInstance()</code> methods or by three public
81 * contructors. Both ways give the option to supply an initial array
82 * of <code>URL</code>s and (optionally) a parent classloader (that is
83 * different from the standard system class loader).</p>
85 * <p>Normally creating a <code>URLClassLoader</code> throws a
86 * <code>SecurityException</code> if a <code>SecurityManager</code> is
87 * installed and the <code>checkCreateClassLoader()</code> method does
88 * not return true. But the <code>newInstance()</code> methods may be
89 * used by any code as long as it has permission to acces the given
90 * <code>URL</code>s. <code>URLClassLoaders</code> created by the
91 * <code>newInstance()</code> methods also explicitly call the
92 * <code>checkPackageAccess()</code> method of
93 * <code>SecurityManager</code> if one is installed before trying to
94 * load a class. Note that only subclasses of
95 * <code>URLClassLoader</code> can add new URLs after the
96 * URLClassLoader had been created. But it is always possible to get
97 * an array of all URLs that the class loader uses to resolve classes
98 * and resources by way of the <code>getURLs()</code> method.</p>
103 * <li>Should the URLClassLoader actually add the locations found in
104 * the manifest or is this the responsibility of some other
105 * loader/(sub)class? (see <a
106 * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html">
107 * Extension Mechanism Architecture - Bundles Extensions</a>)</li>
109 * <li>How does <code>definePackage()</code> and sealing work
112 * <li>We save and use the security context (when a created by
113 * <code>newInstance()</code> but do we have to use it in more
116 * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li>
123 * @author Mark Wielaard (mark@klomp.org)
124 * @author Wu Gansha (gansha.wu@intel.com)
126 public class URLClassLoader
extends SecureClassLoader
131 * A global cache to store mappings between URLLoader and URL,
132 * so we can avoid do all the homework each time the same URL
134 * XXX - Keeps these loaders forever which prevents garbage collection.
136 private static HashMap urlloaders
= new HashMap();
139 * A cache to store mappings between handler factory and its
140 * private protocol handler cache (also a HashMap), so we can avoid
141 * create handlers each time the same protocol comes.
143 private static HashMap factoryCache
= new HashMap(5);
145 // Instance variables
147 /** Locations to load classes from */
148 private final Vector urls
= new Vector();
151 * Store pre-parsed information for each url into this vector: each
152 * element is a URL loader. A jar file has its own class-path
153 * attribute which adds to the URLs that will be searched, but this
154 * does not add to the list of urls.
156 private final Vector urlinfos
= new Vector();
158 /** Factory used to get the protocol handlers of the URLs */
159 private final URLStreamHandlerFactory factory
;
162 * The security context when created from <code>newInstance()</code>
163 * or null when created through a normal constructor or when no
164 * <code>SecurityManager</code> was installed.
166 private final AccessControlContext securityContext
;
171 * A <code>URLLoader</code> contains all logic to load resources from a
172 * given base <code>URL</code>.
174 abstract static class URLLoader
177 * Our classloader to get info from if needed.
179 final URLClassLoader classloader
;
182 * The base URL from which all resources are loaded.
187 * A <code>CodeSource</code> without any associated certificates.
188 * It is common for classes to not have certificates associated
189 * with them. If they come from the same <code>URLLoader</code>
190 * then it is safe to share the associated <code>CodeSource</code>
191 * between them since <code>CodeSource</code> is immutable.
193 final CodeSource noCertCodeSource
;
195 URLLoader(URLClassLoader classloader
, URL baseURL
)
197 this(classloader
, baseURL
, baseURL
);
200 URLLoader(URLClassLoader classloader
, URL baseURL
, URL overrideURL
)
202 this.classloader
= classloader
;
203 this.baseURL
= baseURL
;
204 this.noCertCodeSource
= new CodeSource(overrideURL
, null);
208 * Returns a <code>Class</code> loaded by this
209 * <code>URLLoader</code>, or <code>null</code> when this loader
210 * either can't load the class or doesn't know how to load classes
213 Class
getClass(String className
)
219 * Returns a <code>Resource</code> loaded by this
220 * <code>URLLoader</code>, or <code>null</code> when no
221 * <code>Resource</code> with the given name exists.
223 abstract Resource
getResource(String s
);
226 * Returns the <code>Manifest</code> associated with the
227 * <code>Resource</code>s loaded by this <code>URLLoader</code> or
228 * <code>null</code> there is no such <code>Manifest</code>.
230 Manifest
getManifest()
235 Vector
getClassPath()
242 * A <code>Resource</code> represents a resource in some
243 * <code>URLLoader</code>. It also contains all information (e.g.,
244 * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and
245 * <code>InputStream</code>) that is necessary for loading resources
246 * and creating classes from a <code>URL</code>.
248 abstract static class Resource
250 final URLLoader loader
;
252 Resource(URLLoader loader
)
254 this.loader
= loader
;
258 * Returns the non-null <code>CodeSource</code> associated with
261 CodeSource
getCodeSource()
263 Certificate
[] certs
= getCertificates();
265 return loader
.noCertCodeSource
;
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()
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
,
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);
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
;
406 private final String name
;
408 JarURLResource(JarURLLoader loader
, String name
, JarEntry entry
)
415 InputStream
getInputStream() throws IOException
417 return ((JarURLLoader
) loader
).jarfile
.getInputStream(entry
);
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
430 return ((JarEntry
) ((JarURLLoader
) loader
).jarfile
.getEntry(name
))
438 return new URL(((JarURLLoader
) loader
).baseJarURL
, name
,
439 loader
.classloader
.getURLStreamHandler("jar"));
441 catch (MalformedURLException e
)
443 InternalError ie
= new InternalError();
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
)
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
)
484 ((HttpURLConnection
) connection
).getResponseCode();
485 if (response
/ 100 != 2)
490 return new RemoteResource(this, name
, url
, stream
, length
);
494 catch (IOException ioe
)
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
)
515 this.stream
= stream
;
516 this.length
= length
;
519 InputStream
getInputStream() throws IOException
524 public int getLength()
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
);
565 return new SoResource(this, url
);
569 final static class SoResource
extends Resource
571 SoResource(SoURLLoader loader
, 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.
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
)
616 File file
= new File(dir
, name
).getCanonicalFile();
617 if (file
.exists() && !file
.isDirectory())
618 return new FileResource(this, file
);
620 catch (IOException e
)
628 static final class FileResource
extends Resource
632 FileResource(FileURLLoader loader
, 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())
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())
661 URLConnection connection
= url
.openConnection();
662 return connection
.getContentLength();
664 catch (IOException e
)
669 // Otherwise simply return the file length
670 return (int) file
.length();
679 catch (MalformedURLException e
)
681 InternalError ie
= new InternalError();
689 * A <code>CoreURLLoader</code> is a type of <code>URLLoader</code>
690 * only loading from core url.
692 static final class CoreURLLoader
extends URLLoader
696 CoreURLLoader(URLClassLoader classloader
, URL url
)
698 super(classloader
, url
);
699 dir
= baseURL
.getFile();
702 /** get resource with the name "name" in the core url */
703 Resource
getResource(String name
)
705 Core core
= Core
.find (dir
+ name
);
707 return new CoreResource(this, name
, core
);
712 static final class CoreResource
extends Resource
714 private final Core core
;
715 private final String name
;
717 CoreResource(CoreURLLoader loader
, String name
, Core core
)
724 InputStream
getInputStream() throws IOException
726 return new CoreInputStream(core
);
729 public int getLength()
738 return new URL(loader
.baseURL
, name
,
739 loader
.classloader
.getURLStreamHandler("core"));
741 catch (MalformedURLException e
)
743 InternalError ie
= new InternalError();
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
770 this.securityContext
= null;
775 * Creates a <code>URLClassLoader</code> that gets classes from the supplied
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
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
796 this.securityContext
= null;
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
812 * @param securityContext the security context of the unprivileged code.
814 URLClassLoader(ClassLoader parent
, AccessControlContext securityContext
)
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
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
845 this.securityContext
= null;
846 this.factory
= factory
;
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));
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
)
871 private void addURLImpl(URL newUrl
)
876 return; // Silently ignore...
878 // Reset the toString() value.
881 // Check global cache to see if there're already url loader
883 URLLoader loader
= (URLLoader
) urlloaders
.get(newUrl
);
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.
892 if ("file".equals (protocol
))
894 File dir
= new File(file
);
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
;
915 // This doesn't hurt, and it simplifies the logic a
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
);
930 loader
= new RemoteURLLoader(this, newUrl
);
933 urlloaders
.put(newUrl
, loader
);
936 urlinfos
.add(loader
);
938 Vector extraUrls
= loader
.getClassPath();
939 if (extraUrls
!= null)
941 Iterator it
= extraUrls
.iterator();
944 URL url
= (URL
)it
.next();
945 URLLoader extraLoader
= (URLLoader
) urlloaders
.get(url
);
946 if (! urlinfos
.contains (extraLoader
))
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
,
979 String result
= null;
981 result
= first
.getValue(name
);
983 result
= second
.getValue(name
);
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
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
, '/');
1012 String xformName
= xform
.toString();
1014 Attributes entryAttr
= manifest
.getAttributes(xformName
);
1015 Attributes attr
= manifest
.getMainAttributes();
1018 = getAttributeValue(Attributes
.Name
.SPECIFICATION_TITLE
,
1021 = getAttributeValue(Attributes
.Name
.SPECIFICATION_VERSION
,
1024 = getAttributeValue(Attributes
.Name
.SPECIFICATION_VENDOR
,
1027 = getAttributeValue(Attributes
.Name
.IMPLEMENTATION_TITLE
,
1030 = getAttributeValue(Attributes
.Name
.IMPLEMENTATION_VERSION
,
1033 = getAttributeValue(Attributes
.Name
.IMPLEMENTATION_VENDOR
,
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
1046 return definePackage(name
,
1047 specTitle
, specVendor
, specVersion
,
1048 implTitle
, implVendor
, implVersion
,
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
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
);
1074 Class k
= loader
.getClass(className
);
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)
1096 InputStream in
= resource
.getInputStream();
1099 int length
= resource
.getLength();
1102 // We know the length of the data.
1103 // Just try to read it in all at once
1104 data
= new byte[length
];
1106 while (length
- pos
> 0)
1108 int len
= in
.read(data
, pos
, length
- pos
);
1110 throw new EOFException("Not enough data reading from: "
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];
1128 data
= out
.toByteArray();
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('.');
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,
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()
1167 return defineClass(className
, classData
,
1168 0, classData
.length
,
1171 }, securityContext
);
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
);
1183 catch (IOException ioe
)
1185 ClassNotFoundException cnfe
;
1186 cnfe
= new ClassNotFoundException(className
+ " not found in " + this);
1187 cnfe
.initCause(ioe
);
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
1200 public String
toString()
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)
1217 sb
.append(", parent=");
1218 sb
.append(getParent());
1220 thisString
= sb
.toString();
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
);
1242 Resource resource
= loader
.getResource(resourceName
);
1243 if (resource
!= 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
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)
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)
1286 handler
= factory
.createURLStreamHandler(protocol
);
1287 cache
.put(protocol
, 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
1299 * @exception IOException when an error occurs accessing one of the
1302 public Enumeration
findResources(String resourceName
)
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"));
1360 // It is a 'normal' file.
1361 // Grant permission to access that file.
1362 permissions
.add(new FilePermission(file
, "read"));
1367 // Grant permission to connect to and accept connections from host
1368 String host
= url
.getHost();
1370 permissions
.add(new SocketPermission(host
, "connect,accept"));
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
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
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();
1425 return new URLClassLoader(urls
, parent
);
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: "
1435 URLClassLoader loader
=
1436 (URLClassLoader
) AccessController
.doPrivileged(new PrivilegedAction()
1440 return new URLClassLoader(parent
,
1441 (AccessControlContext
) securityContext
);
1444 loader
.addURLs(urls
);