1 /* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
42 import java
.io
.ByteArrayOutputStream
;
43 import java
.io
.EOFException
;
45 import java
.io
.FileInputStream
;
46 import java
.io
.FilePermission
;
47 import java
.io
.IOException
;
48 import java
.io
.InputStream
;
49 import java
.security
.AccessControlContext
;
50 import java
.security
.AccessController
;
51 import java
.security
.CodeSource
;
52 import java
.security
.PermissionCollection
;
53 import java
.security
.PrivilegedAction
;
54 import java
.security
.SecureClassLoader
;
55 import java
.security
.cert
.Certificate
;
56 import java
.util
.Enumeration
;
57 import java
.util
.HashMap
;
58 import java
.util
.Iterator
;
59 import java
.util
.StringTokenizer
;
60 import java
.util
.Vector
;
61 import java
.util
.jar
.Attributes
;
62 import java
.util
.jar
.JarEntry
;
63 import java
.util
.jar
.JarFile
;
64 import java
.util
.jar
.Manifest
;
65 import gnu
.gcj
.runtime
.SharedLibHelper
;
69 * A secure class loader that can load classes and resources from
70 * multiple locations. Given an array of <code>URL</code>s this class
71 * loader will retrieve classes and resources by fetching them from
72 * possible remote locations. Each <code>URL</code> is searched in
73 * order in which it was added. If the file portion of the
74 * <code>URL</code> ends with a '/' character then it is interpreted
75 * as a base directory, otherwise it is interpreted as a jar file from
76 * which the classes/resources are resolved.
78 * <p>New instances can be created by two static
79 * <code>newInstance()</code> methods or by three public
80 * contructors. Both ways give the option to supply an initial array
81 * of <code>URL</code>s and (optionally) a parent classloader (that is
82 * different from the standard system class loader).</p>
84 * <p>Normally creating a <code>URLClassLoader</code> throws a
85 * <code>SecurityException</code> if a <code>SecurityManager</code> is
86 * installed and the <code>checkCreateClassLoader()</code> method does
87 * not return true. But the <code>newInstance()</code> methods may be
88 * used by any code as long as it has permission to acces the given
89 * <code>URL</code>s. <code>URLClassLoaders</code> created by the
90 * <code>newInstance()</code> methods also explicitly call the
91 * <code>checkPackageAccess()</code> method of
92 * <code>SecurityManager</code> if one is installed before trying to
93 * load a class. Note that only subclasses of
94 * <code>URLClassLoader</code> can add new URLs after the
95 * URLClassLoader had been created. But it is always possible to get
96 * an array of all URLs that the class loader uses to resolve classes
97 * and resources by way of the <code>getURLs()</code> method.</p>
102 * <li>Should the URLClassLoader actually add the locations found in
103 * the manifest or is this the responsibility of some other
104 * loader/(sub)class? (see <a
105 * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html">
106 * Extension Mechanism Architecture - Bundles Extensions</a>)</li>
108 * <li>How does <code>definePackage()</code> and sealing work
111 * <li>We save and use the security context (when a created by
112 * <code>newInstance()</code> but do we have to use it in more
115 * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li>
122 * @author Mark Wielaard (mark@klomp.org)
123 * @author Wu Gansha (gansha.wu@intel.com)
125 public class URLClassLoader
extends SecureClassLoader
130 * A global cache to store mappings between URLLoader and URL,
131 * so we can avoid do all the homework each time the same URL
133 * XXX - Keeps these loaders forever which prevents garbage collection.
135 private static HashMap urlloaders
= new HashMap();
138 * A cache to store mappings between handler factory and its
139 * private protocol handler cache (also a HashMap), so we can avoid
140 * create handlers each time the same protocol comes.
142 private static HashMap factoryCache
= new HashMap(5);
144 // Instance variables
146 /** Locations to load classes from */
147 private final Vector urls
= new Vector();
150 * Store pre-parsed information for each url into this vector: each
151 * element is a URL loader. A jar file has its own class-path
152 * attribute which adds to the URLs that will be searched, but this
153 * does not add to the list of urls.
155 private final Vector urlinfos
= new Vector();
157 /** Factory used to get the protocol handlers of the URLs */
158 private final URLStreamHandlerFactory factory
;
161 * The security context when created from <code>newInstance()</code>
162 * or null when created through a normal constructor or when no
163 * <code>SecurityManager</code> was installed.
165 private final AccessControlContext securityContext
;
170 * A <code>URLLoader</code> contains all logic to load resources from a
171 * given base <code>URL</code>.
173 abstract static class URLLoader
176 * Our classloader to get info from if needed.
178 final URLClassLoader classloader
;
181 * The base URL from which all resources are loaded.
186 * A <code>CodeSource</code> without any associated certificates.
187 * It is common for classes to not have certificates associated
188 * with them. If they come from the same <code>URLLoader</code>
189 * then it is safe to share the associated <code>CodeSource</code>
190 * between them since <code>CodeSource</code> is immutable.
192 final CodeSource noCertCodeSource
;
194 URLLoader(URLClassLoader classloader
, URL baseURL
)
196 this(classloader
, baseURL
, baseURL
);
199 URLLoader(URLClassLoader classloader
, URL baseURL
, URL overrideURL
)
201 this.classloader
= classloader
;
202 this.baseURL
= baseURL
;
203 this.noCertCodeSource
= new CodeSource(overrideURL
, null);
207 * Returns a <code>Class</code> loaded by this
208 * <code>URLLoader</code>, or <code>null</code> when this loader
209 * either can't load the class or doesn't know how to load classes
212 Class
getClass(String className
)
218 * Returns a <code>Resource</code> loaded by this
219 * <code>URLLoader</code>, or <code>null</code> when no
220 * <code>Resource</code> with the given name exists.
222 abstract Resource
getResource(String s
);
225 * Returns the <code>Manifest</code> associated with the
226 * <code>Resource</code>s loaded by this <code>URLLoader</code> or
227 * <code>null</code> there is no such <code>Manifest</code>.
229 Manifest
getManifest()
234 Vector
getClassPath()
241 * A <code>Resource</code> represents a resource in some
242 * <code>URLLoader</code>. It also contains all information (e.g.,
243 * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and
244 * <code>InputStream</code>) that is necessary for loading resources
245 * and creating classes from a <code>URL</code>.
247 abstract static class Resource
249 final URLLoader loader
;
252 Resource(URLLoader loader
, String name
)
254 this.loader
= loader
;
259 * Returns the non-null <code>CodeSource</code> associated with
262 CodeSource
getCodeSource()
264 Certificate
[] certs
= getCertificates();
266 return loader
.noCertCodeSource
;
268 return new CodeSource(loader
.baseURL
, certs
);
272 * Returns <code>Certificates</code> associated with this
273 * resource, or null when there are none.
275 Certificate
[] getCertificates()
281 * Return a <code>URL</code> that can be used to access this resource.
283 abstract URL
getURL();
286 * Returns the size of this <code>Resource</code> in bytes or
287 * <code>-1</code> when unknown.
289 abstract int getLength();
292 * Returns the non-null <code>InputStream</code> through which
293 * this resource can be loaded.
295 abstract InputStream
getInputStream() throws IOException
;
299 * A <code>JarURLLoader</code> is a type of <code>URLLoader</code>
300 * only loading from jar url.
302 static final class JarURLLoader
extends URLLoader
304 final JarFile jarfile
; // The jar file for this url
305 final URL baseJarURL
; // Base jar: url for all resources loaded from jar
307 Vector classPath
; // The "Class-Path" attribute of this Jar's manifest
309 public JarURLLoader(URLClassLoader classloader
, URL baseURL
)
311 super(classloader
, baseURL
);
313 // Cache url prefix for all resources in this jar url.
314 String external
= baseURL
.toExternalForm();
315 StringBuffer sb
= new StringBuffer(external
.length() + 6);
319 String jarURL
= sb
.toString();
321 this.classPath
= null;
322 URL baseJarURL
= null;
323 JarFile jarfile
= null;
327 new URL(null, jarURL
, classloader
.getURLStreamHandler("jar"));
330 ((JarURLConnection
) baseJarURL
.openConnection()).getJarFile();
333 Attributes attributes
;
334 String classPathString
;
336 if ((manifest
= jarfile
.getManifest()) != null
337 && (attributes
= manifest
.getMainAttributes()) != null
339 = attributes
.getValue(Attributes
.Name
.CLASS_PATH
))
342 this.classPath
= new Vector();
344 StringTokenizer st
= new StringTokenizer(classPathString
, " ");
345 while (st
.hasMoreElements ())
347 String e
= st
.nextToken ();
350 URL url
= new URL(baseURL
, e
);
351 this.classPath
.add(url
);
353 catch (java
.net
.MalformedURLException xx
)
360 catch (IOException ioe
)
365 this.baseJarURL
= baseJarURL
;
366 this.jarfile
= jarfile
;
369 /** get resource with the name "name" in the jar url */
370 Resource
getResource(String name
)
375 if (name
.startsWith("/"))
376 name
= name
.substring(1);
378 JarEntry je
= jarfile
.getJarEntry(name
);
380 return new JarURLResource(this, name
, je
);
385 Manifest
getManifest()
389 return (jarfile
== null) ?
null : jarfile
.getManifest();
391 catch (IOException ioe
)
397 Vector
getClassPath()
403 static final class JarURLResource
extends Resource
405 private final JarEntry entry
;
407 JarURLResource(JarURLLoader loader
, String name
, JarEntry entry
)
413 InputStream
getInputStream() throws IOException
415 return ((JarURLLoader
) loader
).jarfile
.getInputStream(entry
);
420 return (int) entry
.getSize();
423 Certificate
[] getCertificates()
425 // We have to get the entry from the jar file again, because the
426 // certificates will not be available until the entire entry has
428 return ((JarEntry
) ((JarURLLoader
) loader
).jarfile
.getEntry(name
))
436 return new URL(((JarURLLoader
) loader
).baseJarURL
, name
,
437 loader
.classloader
.getURLStreamHandler("jar"));
439 catch (MalformedURLException e
)
441 InternalError ie
= new InternalError();
449 * Loader for remote directories.
451 static final class RemoteURLLoader
extends URLLoader
453 private final String protocol
;
455 RemoteURLLoader(URLClassLoader classloader
, URL url
)
457 super(classloader
, url
);
458 protocol
= url
.getProtocol();
462 * Get a remote resource.
463 * Returns null if no such resource exists.
465 Resource
getResource(String name
)
470 new URL(baseURL
, name
, classloader
.getURLStreamHandler(protocol
));
471 URLConnection connection
= url
.openConnection();
473 // Open the connection and check the stream
474 // just to be sure it exists.
475 int length
= connection
.getContentLength();
476 InputStream stream
= connection
.getInputStream();
478 // We can do some extra checking if it is a http request
479 if (connection
instanceof HttpURLConnection
)
482 ((HttpURLConnection
) connection
).getResponseCode();
483 if (response
/ 100 != 2)
488 return new RemoteResource(this, name
, url
, stream
, length
);
492 catch (IOException ioe
)
500 * A resource from some remote location.
502 static final class RemoteResource
extends Resource
504 private final URL url
;
505 private final InputStream stream
;
506 private final int length
;
508 RemoteResource(RemoteURLLoader loader
, String name
, URL url
,
509 InputStream stream
, int length
)
513 this.stream
= stream
;
514 this.length
= length
;
517 InputStream
getInputStream() throws IOException
522 public int getLength()
534 * A <code>SoURLLoader</code> is a type of <code>URLLoader</code>
535 * that loads classes and resources from a shared library.
537 final static class SoURLLoader
extends URLLoader
539 SharedLibHelper helper
;
541 SoURLLoader(URLClassLoader classloader
, URL url
)
543 this(classloader
, url
, url
);
546 SoURLLoader(URLClassLoader classloader
, URL url
, URL overrideURL
)
548 super(classloader
, url
, overrideURL
);
549 helper
= SharedLibHelper
.findHelper(classloader
, url
.getFile(),
550 noCertCodeSource
, true);
553 Class
getClass(String className
)
555 return helper
.findClass(className
);
558 Resource
getResource(String name
)
560 URL url
= helper
.findResource(name
);
563 return new SoResource(this, name
, url
);
567 final static class SoResource
extends Resource
569 SoResource(SoURLLoader loader
, String name
, URL url
)
575 InputStream
getInputStream() throws IOException
577 URLConnection conn
= url
.openConnection();
578 return conn
.getInputStream();
581 public int getLength()
583 // FIXME we could find this by asking the core object.
596 * A <code>FileURLLoader</code> is a type of <code>URLLoader</code>
597 * only loading from file url.
599 static final class FileURLLoader
extends URLLoader
601 File dir
; //the file for this file url
603 FileURLLoader(URLClassLoader classloader
, URL url
)
605 super(classloader
, url
);
606 dir
= new File(baseURL
.getFile());
609 /** get resource with the name "name" in the file url */
610 Resource
getResource(String name
)
612 File file
= new File(dir
, name
);
613 if (file
.exists() && ! file
.isDirectory())
614 return new FileResource(this, name
, file
);
619 static final class FileResource
extends Resource
623 FileResource(FileURLLoader loader
, String name
, File file
)
629 InputStream
getInputStream() throws IOException
631 return new FileInputStream(file
);
634 public int getLength()
636 return (int) file
.length();
643 return new URL(loader
.baseURL
, name
,
644 loader
.classloader
.getURLStreamHandler("file"));
646 catch (MalformedURLException e
)
648 InternalError ie
= new InternalError();
658 * Creates a URLClassLoader that gets classes from the supplied URLs.
659 * To determine if this classloader may be created the constructor of
660 * the super class (<code>SecureClassLoader</code>) is called first, which
661 * can throw a SecurityException. Then the supplied URLs are added
662 * in the order given to the URLClassLoader which uses these URLs to
663 * load classes and resources (after using the default parent ClassLoader).
665 * @exception SecurityException if the SecurityManager disallows the
666 * creation of a ClassLoader.
667 * @param urls Locations that should be searched by this ClassLoader when
668 * resolving Classes or Resources.
669 * @see SecureClassLoader
671 public URLClassLoader(URL
[] urls
) throws SecurityException
675 this.securityContext
= null;
680 * Private constructor used by the static
681 * <code>newInstance(URL[])</code> method. Creates an
682 * <code>URLClassLoader</code> without any <code>URL</code>s
683 * yet. This is used to bypass the normal security check for
684 * creating classloaders, but remembers the security context which
685 * will be used when defining classes. The <code>URL</code>s to
686 * load from must be added by the <code>newInstance()</code> method
687 * in the security context of the caller.
689 * @param securityContext the security context of the unprivileged code.
691 private URLClassLoader(AccessControlContext securityContext
)
695 this.securityContext
= securityContext
;
699 * Creates a <code>URLClassLoader</code> that gets classes from the supplied
701 * To determine if this classloader may be created the constructor of
702 * the super class (<code>SecureClassLoader</code>) is called first, which
703 * can throw a SecurityException. Then the supplied URLs are added
704 * in the order given to the URLClassLoader which uses these URLs to
705 * load classes and resources (after using the supplied parent ClassLoader).
706 * @exception SecurityException if the SecurityManager disallows the
707 * creation of a ClassLoader.
708 * @exception SecurityException
709 * @param urls Locations that should be searched by this ClassLoader when
710 * resolving Classes or Resources.
711 * @param parent The parent class loader used before trying this class
713 * @see SecureClassLoader
715 public URLClassLoader(URL
[] urls
, ClassLoader parent
)
716 throws SecurityException
720 this.securityContext
= null;
724 // Package-private to avoid a trampoline constructor.
726 * Package-private constructor used by the static
727 * <code>newInstance(URL[])</code> method. Creates an
728 * <code>URLClassLoader</code> with the given parent but without any
729 * <code>URL</code>s yet. This is used to bypass the normal security
730 * check for creating classloaders, but remembers the security
731 * context which will be used when defining classes. The
732 * <code>URL</code>s to load from must be added by the
733 * <code>newInstance()</code> method in the security context of the
736 * @param securityContext the security context of the unprivileged code.
738 URLClassLoader(ClassLoader parent
, AccessControlContext securityContext
)
742 this.securityContext
= securityContext
;
746 * Creates a URLClassLoader that gets classes from the supplied URLs.
747 * To determine if this classloader may be created the constructor of
748 * the super class (<CODE>SecureClassLoader</CODE>) is called first, which
749 * can throw a SecurityException. Then the supplied URLs are added
750 * in the order given to the URLClassLoader which uses these URLs to
751 * load classes and resources (after using the supplied parent ClassLoader).
752 * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the
753 * protocol handlers of the supplied URLs.
754 * @exception SecurityException if the SecurityManager disallows the
755 * creation of a ClassLoader.
756 * @exception SecurityException
757 * @param urls Locations that should be searched by this ClassLoader when
758 * resolving Classes or Resources.
759 * @param parent The parent class loader used before trying this class
761 * @param factory Used to get the protocol handler for the URLs.
762 * @see SecureClassLoader
764 public URLClassLoader(URL
[] urls
, ClassLoader parent
,
765 URLStreamHandlerFactory factory
)
766 throws SecurityException
769 this.securityContext
= null;
770 this.factory
= factory
;
773 // If this factory is still not in factoryCache, add it,
774 // since we only support three protocols so far, 5 is enough
775 // for cache initial size
776 synchronized (factoryCache
)
778 if (factory
!= null && factoryCache
.get(factory
) == null)
779 factoryCache
.put(factory
, new HashMap(5));
786 * Adds a new location to the end of the internal URL store.
787 * @param newUrl the location to add
789 protected void addURL(URL newUrl
)
795 private void addURLImpl(URL newUrl
)
797 synchronized (urlloaders
)
800 return; // Silently ignore...
802 // Check global cache to see if there're already url loader
804 URLLoader loader
= (URLLoader
) urlloaders
.get(newUrl
);
807 String file
= newUrl
.getFile();
808 String protocol
= newUrl
.getProtocol();
810 // Check that it is not a directory
811 if ("gcjlib".equals(protocol
))
812 loader
= new SoURLLoader(this, newUrl
);
813 else if (! (file
.endsWith("/") || file
.endsWith(File
.separator
)))
814 loader
= new JarURLLoader(this, newUrl
);
815 else if ("file".equals(protocol
))
816 loader
= new FileURLLoader(this, newUrl
);
818 loader
= new RemoteURLLoader(this, newUrl
);
821 urlloaders
.put(newUrl
, loader
);
824 urlinfos
.add(loader
);
826 Vector extraUrls
= loader
.getClassPath();
827 if (extraUrls
!= null)
829 Iterator it
= extraUrls
.iterator();
832 URL url
= (URL
)it
.next();
833 URLLoader extraLoader
= (URLLoader
) urlloaders
.get(url
);
834 if (! urlinfos
.contains (extraLoader
))
843 * Adds an array of new locations to the end of the internal URL store.
844 * @param newUrls the locations to add
846 private void addURLs(URL
[] newUrls
)
848 for (int i
= 0; i
< newUrls
.length
; i
++)
853 * Defines a Package based on the given name and the supplied manifest
854 * information. The manifest indicates the tile, version and
855 * vendor information of the specification and implementation and wheter the
856 * package is sealed. If the Manifest indicates that the package is sealed
857 * then the Package will be sealed with respect to the supplied URL.
859 * @exception IllegalArgumentException If this package name already exists
860 * in this class loader
861 * @param name The name of the package
862 * @param manifest The manifest describing the specification,
863 * implementation and sealing details of the package
864 * @param url the code source url to seal the package
865 * @return the defined Package
867 protected Package
definePackage(String name
, Manifest manifest
, URL url
)
868 throws IllegalArgumentException
870 Attributes attr
= manifest
.getMainAttributes();
871 String specTitle
= attr
.getValue(Attributes
.Name
.SPECIFICATION_TITLE
);
872 String specVersion
= attr
.getValue(Attributes
.Name
.SPECIFICATION_VERSION
);
873 String specVendor
= attr
.getValue(Attributes
.Name
.SPECIFICATION_VENDOR
);
874 String implTitle
= attr
.getValue(Attributes
.Name
.IMPLEMENTATION_TITLE
);
875 String implVersion
= attr
.getValue(Attributes
.Name
.IMPLEMENTATION_VERSION
);
876 String implVendor
= attr
.getValue(Attributes
.Name
.IMPLEMENTATION_VENDOR
);
878 // Look if the Manifest indicates that this package is sealed
879 // XXX - most likely not completely correct!
880 // Shouldn't we also check the sealed attribute of the complete jar?
881 // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled
882 // But how do we get that jar manifest here?
883 String sealed
= attr
.getValue(Attributes
.Name
.SEALED
);
884 if ("false".equals(sealed
))
885 // make sure that the URL is null so the package is not sealed
888 return definePackage(name
, specTitle
, specVersion
, specVendor
, implTitle
,
889 implVersion
, implVendor
, url
);
893 * Finds (the first) class by name from one of the locations. The locations
894 * are searched in the order they were added to the URLClassLoader.
896 * @param className the classname to find
897 * @exception ClassNotFoundException when the class could not be found or
899 * @return a Class object representing the found class
901 protected Class
findClass(final String className
)
902 throws ClassNotFoundException
904 // Just try to find the resource by the (almost) same name
905 String resourceName
= className
.replace('.', '/') + ".class";
906 int max
= urlinfos
.size();
907 Resource resource
= null;
908 for (int i
= 0; i
< max
&& resource
== null; i
++)
910 URLLoader loader
= (URLLoader
)urlinfos
.elementAt(i
);
914 Class k
= loader
.getClass(className
);
918 resource
= loader
.getResource(resourceName
);
920 if (resource
== null)
921 throw new ClassNotFoundException(className
+ " not found in " + this);
923 // Try to read the class data, create the CodeSource, Package and
924 // construct the class (and watch out for those nasty IOExceptions)
928 InputStream in
= resource
.getInputStream();
929 int length
= resource
.getLength();
932 // We know the length of the data.
933 // Just try to read it in all at once
934 data
= new byte[length
];
936 while (length
- pos
> 0)
938 int len
= in
.read(data
, pos
, length
- pos
);
940 throw new EOFException("Not enough data reading from: "
947 // We don't know the data length.
948 // Have to read it in chunks.
949 ByteArrayOutputStream out
= new ByteArrayOutputStream(4096);
950 byte[] b
= new byte[4096];
958 data
= out
.toByteArray();
960 final byte[] classData
= data
;
962 // Now get the CodeSource
963 final CodeSource source
= resource
.getCodeSource();
965 // Find out package name
966 String packageName
= null;
967 int lastDot
= className
.lastIndexOf('.');
969 packageName
= className
.substring(0, lastDot
);
971 if (packageName
!= null && getPackage(packageName
) == null)
973 // define the package
974 Manifest manifest
= resource
.loader
.getManifest();
975 if (manifest
== null)
976 definePackage(packageName
, null, null, null, null, null, null,
979 definePackage(packageName
, manifest
, resource
.loader
.baseURL
);
982 // And finally construct the class!
983 SecurityManager sm
= System
.getSecurityManager();
985 if (sm
!= null && securityContext
!= null)
987 result
= (Class
)AccessController
.doPrivileged
988 (new PrivilegedAction()
992 return defineClass(className
, classData
,
999 result
= defineClass(className
, classData
, 0, classData
.length
, source
);
1001 super.setSigners(result
, resource
.getCertificates());
1004 catch (IOException ioe
)
1006 ClassNotFoundException cnfe
;
1007 cnfe
= new ClassNotFoundException(className
+ " not found in " + this);
1008 cnfe
.initCause(ioe
);
1013 // Cached String representation of this URLClassLoader
1014 private String thisString
;
1017 * Returns a String representation of this URLClassLoader giving the
1018 * actual Class name, the URLs that are searched and the parent
1021 public String
toString()
1023 if (thisString
== null)
1025 StringBuffer sb
= new StringBuffer();
1026 sb
.append(this.getClass().getName());
1027 sb
.append("{urls=[" );
1028 URL
[] thisURLs
= getURLs();
1029 for (int i
= 0; i
< thisURLs
.length
; i
++)
1031 sb
.append(thisURLs
[i
]);
1032 if (i
< thisURLs
.length
- 1)
1036 sb
.append(", parent=");
1037 sb
.append(getParent());
1039 thisString
= sb
.toString();
1045 * Finds the first occurrence of a resource that can be found. The locations
1046 * are searched in the order they were added to the URLClassLoader.
1048 * @param resourceName the resource name to look for
1049 * @return the URLResource for the resource if found, null otherwise
1051 private Resource
findURLResource(String resourceName
)
1053 int max
= urlinfos
.size();
1054 for (int i
= 0; i
< max
; i
++)
1056 URLLoader loader
= (URLLoader
) urlinfos
.elementAt(i
);
1060 Resource resource
= loader
.getResource(resourceName
);
1061 if (resource
!= null)
1068 * Finds the first occurrence of a resource that can be found.
1070 * @param resourceName the resource name to look for
1071 * @return the URL if found, null otherwise
1073 public URL
findResource(String resourceName
)
1075 Resource resource
= findURLResource(resourceName
);
1076 if (resource
!= null)
1077 return resource
.getURL();
1079 // Resource not found
1084 * If the URLStreamHandlerFactory has been set this return the appropriate
1085 * URLStreamHandler for the given protocol, if not set returns null.
1087 * @param protocol the protocol for which we need a URLStreamHandler
1088 * @return the appropriate URLStreamHandler or null
1090 URLStreamHandler
getURLStreamHandler(String protocol
)
1092 if (factory
== null)
1095 URLStreamHandler handler
;
1096 synchronized (factoryCache
)
1098 // Check if there're handler for the same protocol in cache.
1099 HashMap cache
= (HashMap
) factoryCache
.get(factory
);
1100 handler
= (URLStreamHandler
) cache
.get(protocol
);
1101 if (handler
== null)
1104 handler
= factory
.createURLStreamHandler(protocol
);
1105 cache
.put(protocol
, handler
);
1112 * Finds all the resources with a particular name from all the locations.
1114 * @exception IOException when an error occurs accessing one of the
1116 * @param resourceName the name of the resource to lookup
1117 * @return a (possible empty) enumeration of URLs where the resource can be
1120 public Enumeration
findResources(String resourceName
)
1123 Vector resources
= new Vector();
1124 int max
= urlinfos
.size();
1125 for (int i
= 0; i
< max
; i
++)
1127 URLLoader loader
= (URLLoader
) urlinfos
.elementAt(i
);
1128 Resource resource
= loader
.getResource(resourceName
);
1129 if (resource
!= null)
1130 resources
.add(resource
.getURL());
1132 return resources
.elements();
1136 * Returns the permissions needed to access a particular code
1137 * source. These permissions includes those returned by
1138 * <code>SecureClassLoader.getPermissions()</code> and the actual
1139 * permissions to access the objects referenced by the URL of the
1140 * code source. The extra permissions added depend on the protocol
1141 * and file portion of the URL in the code source. If the URL has
1142 * the "file" protocol ends with a '/' character then it must be a
1143 * directory and a file Permission to read everything in that
1144 * directory and all subdirectories is added. If the URL had the
1145 * "file" protocol and doesn't end with a '/' character then it must
1146 * be a normal file and a file permission to read that file is
1147 * added. If the <code>URL</code> has any other protocol then a
1148 * socket permission to connect and accept connections from the host
1149 * portion of the URL is added.
1151 * @param source The codesource that needs the permissions to be accessed
1152 * @return the collection of permissions needed to access the code resource
1153 * @see java.security.SecureClassLoader#getPermissions()
1155 protected PermissionCollection
getPermissions(CodeSource source
)
1157 // XXX - This implementation does exactly as the Javadoc describes.
1158 // But maybe we should/could use URLConnection.getPermissions()?
1159 // First get the permissions that would normally be granted
1160 PermissionCollection permissions
= super.getPermissions(source
);
1162 // Now add any extra permissions depending on the URL location.
1163 URL url
= source
.getLocation();
1164 String protocol
= url
.getProtocol();
1165 if (protocol
.equals("file"))
1167 String file
= url
.getFile();
1169 // If the file end in / it must be an directory.
1170 if (file
.endsWith("/") || file
.endsWith(File
.separator
))
1172 // Grant permission to read everything in that directory and
1173 // all subdirectories.
1174 permissions
.add(new FilePermission(file
+ "-", "read"));
1178 // It is a 'normal' file.
1179 // Grant permission to access that file.
1180 permissions
.add(new FilePermission(file
, "read"));
1185 // Grant permission to connect to and accept connections from host
1186 String host
= url
.getHost();
1188 permissions
.add(new SocketPermission(host
, "connect,accept"));
1195 * Returns all the locations that this class loader currently uses the
1196 * resolve classes and resource. This includes both the initially supplied
1197 * URLs as any URLs added later by the loader.
1198 * @return All the currently used URLs
1200 public URL
[] getURLs()
1202 return (URL
[]) urls
.toArray(new URL
[urls
.size()]);
1206 * Creates a new instance of a <code>URLClassLoader</code> that gets
1207 * classes from the supplied <code>URL</code>s. This class loader
1208 * will have as parent the standard system class loader.
1210 * @param urls the initial URLs used to resolve classes and
1213 * @return the class loader
1215 * @exception SecurityException when the calling code does not have
1216 * permission to access the given <code>URL</code>s
1218 public static URLClassLoader
newInstance(URL
[] urls
)
1219 throws SecurityException
1221 return newInstance(urls
, null);
1225 * Creates a new instance of a <code>URLClassLoader</code> that gets
1226 * classes from the supplied <code>URL</code>s and with the supplied
1227 * loader as parent class loader.
1229 * @param urls the initial URLs used to resolve classes and
1231 * @param parent the parent class loader
1233 * @return the class loader
1235 * @exception SecurityException when the calling code does not have
1236 * permission to access the given <code>URL</code>s
1238 public static URLClassLoader
newInstance(URL
[] urls
, final ClassLoader parent
)
1239 throws SecurityException
1241 SecurityManager sm
= System
.getSecurityManager();
1243 return new URLClassLoader(urls
, parent
);
1246 final Object securityContext
= sm
.getSecurityContext();
1248 // XXX - What to do with anything else then an AccessControlContext?
1249 if (! (securityContext
instanceof AccessControlContext
))
1250 throw new SecurityException("securityContext must be AccessControlContext: "
1253 URLClassLoader loader
=
1254 (URLClassLoader
) AccessController
.doPrivileged(new PrivilegedAction()
1258 return new URLClassLoader(parent
,
1259 (AccessControlContext
) securityContext
);
1262 loader
.addURLs(urls
);