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