source: trunk/gcc/libjava/java/net/URLClassLoader.java

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 32.3 KB
Line 
1/* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs
2 Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3
4This file is part of GNU Classpath.
5
6GNU Classpath is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Classpath is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Classpath; see the file COPYING. If not, write to the
18Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1902111-1307 USA.
20
21Linking this library statically or dynamically with other modules is
22making a combined work based on this library. Thus, the terms and
23conditions of the GNU General Public License cover the whole
24combination.
25
26As a special exception, the copyright holders of this library give you
27permission to link this library with independent modules to produce an
28executable, regardless of the license terms of these independent
29modules, and to copy and distribute the resulting executable under
30terms of your choice, provided that you also meet, for each linked
31independent module, the terms and conditions of the license of that
32module. An independent module is a module which is not derived from
33or based on this library. If you modify this library, you may extend
34this exception to your version of the library, but you are not
35obligated to do so. If you do not wish to do so, delete this
36exception statement from your version. */
37
38package java.net;
39
40import java.io.ByteArrayOutputStream;
41import java.io.EOFException;
42import java.io.File;
43import java.io.FileInputStream;
44import java.io.FileNotFoundException;
45import java.io.FilterInputStream;
46import java.io.FilePermission;
47import java.io.InputStream;
48import java.io.IOException;
49import java.security.AccessController;
50import java.security.AccessControlContext;
51import java.security.CodeSource;
52import java.security.SecureClassLoader;
53import java.security.PrivilegedAction;
54import java.security.PermissionCollection;
55import java.security.cert.Certificate;
56import java.util.Enumeration;
57import java.util.Vector;
58import java.util.HashMap;
59import java.util.jar.Attributes;
60import java.util.jar.JarEntry;
61import java.util.jar.JarFile;
62import java.util.jar.Manifest;
63import java.util.zip.ZipException;
64
65/**
66 * A secure class loader that can load classes and resources from
67 * multiple locations. Given an array of <code>URL</code>s this class
68 * loader will retrieve classes and resources by fetching them from
69 * possible remote locations. Each <code>URL</code> is searched in
70 * order in which it was added. If the file portion of the
71 * <code>URL</code> ends with a '/' character then it is interpreted
72 * as a base directory, otherwise it is interpreted as a jar file from
73 * which the classes/resources are resolved.
74 *
75 * <p>New instances can be created by two static
76 * <code>newInstance()</code> methods or by three public
77 * contructors. Both ways give the option to supply an initial array
78 * of <code>URL</code>s and (optionally) a parent classloader (that is
79 * different from the standard system class loader).</p>
80 *
81 * <p>Normally creating a <code>URLClassLoader</code> throws a
82 * <code>SecurityException</code> if a <code>SecurityManager</code> is
83 * installed and the <code>checkCreateClassLoader()</code> method does
84 * not return true. But the <code>newInstance()</code> methods may be
85 * used by any code as long as it has permission to acces the given
86 * <code>URL</code>s. <code>URLClassLoaders</code> created by the
87 * <code>newInstance()</code> methods also explicitly call the
88 * <code>checkPackageAccess()</code> method of
89 * <code>SecurityManager</code> if one is installed before trying to
90 * load a class. Note that only subclasses of
91 * <code>URLClassLoader</code> can add new URLs after the
92 * URLClassLoader had been created. But it is always possible to get
93 * an array of all URLs that the class loader uses to resolve classes
94 * and resources by way of the <code>getURLs()</code> method.</p>
95 *
96 * <p>Open issues:
97 * <ul>
98 *
99 * <li>Should the URLClassLoader actually add the locations found in
100 * the manifest or is this the responsibility of some other
101 * loader/(sub)class? (see <a
102 * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html">
103 * Extension Mechanism Architecture - Bundles Extensions</a>)</li>
104 *
105 * <li>How does <code>definePackage()</code> and sealing work
106 * precisely?</li>
107 *
108 * <li>We save and use the security context (when a created by
109 * <code>newInstance()</code> but do we have to use it in more
110 * places?</li>
111 *
112 * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li>
113 *
114 * </ul>
115 * </p>
116 *
117 * @since 1.2
118 *
119 * @author Mark Wielaard (mark@klomp.org)
120 * @author Wu Gansha (gansha.wu@intel.com)
121 */
122
123public class URLClassLoader extends SecureClassLoader
124{
125 // Class Variables
126
127 /**
128 * A global cache to store mappings between URLLoader and URL,
129 * so we can avoid do all the homework each time the same URL
130 * comes.
131 * XXX - Keeps these loaders forever which prevents garbage collection.
132 */
133 private static HashMap urlloaders = new HashMap();
134
135 /**
136 * A cache to store mappings between handler factory and its
137 * private protocol handler cache (also a HashMap), so we can avoid
138 * create handlers each time the same protocol comes.
139 */
140 private static HashMap factoryCache = new HashMap(5);
141
142 // Instance variables
143
144 /** Locations to load classes from */
145 private final Vector urls = new Vector();
146
147 /**
148 * Store pre-parsed information for each url into this vector
149 * each element is a URL loader, corresponding to the URL of
150 * the same index in "urls"
151 */
152 private final Vector urlinfos = new Vector();
153
154 /** Factory used to get the protocol handlers of the URLs */
155 private final URLStreamHandlerFactory factory;
156
157 /**
158 * The security context when created from <code>newInstance()</code>
159 * or null when created through a normal constructor or when no
160 * <code>SecurityManager</code> was installed.
161 */
162 private final AccessControlContext securityContext;
163
164 // Helper classes
165
166 /**
167 * A <code>URLLoader</code> contains all logic to load resources from a
168 * given base <code>URL</code>.
169 */
170 static abstract class URLLoader
171 {
172 /**
173 * Our classloader to get info from if needed.
174 */
175 final URLClassLoader classloader;
176
177 /**
178 * The base URL from which all resources are loaded.
179 */
180 final URL baseURL;
181
182 /**
183 * A <code>CodeSource</code> without any associated certificates.
184 * It is common for classes to not have certificates associated
185 * with them. If they come from the same <code>URLLoader</code>
186 * then it is safe to share the associated <code>CodeSource</code>
187 * between them since <code>CodeSource</code> is immutable.
188 */
189 final CodeSource noCertCodeSource;
190
191 URLLoader(URLClassLoader classloader, URL baseURL)
192 {
193 this.classloader = classloader;
194 this.baseURL = baseURL;
195 this.noCertCodeSource = new CodeSource(baseURL, null);
196 }
197
198 /**
199 * Returns a <code>Resource</code> loaded by this
200 * <code>URLLoader</code>, or <code>null</code> when no
201 * <code>Resource</code> with the given name exists.
202 */
203 abstract Resource getResource(String s);
204
205 /**
206 * Returns the <code>Manifest</code> associated with the
207 * <code>Resource</code>s loaded by this <code>URLLoader</code> or
208 * <code>null</code> there is no such <code>Manifest</code>.
209 */
210 Manifest getManifest()
211 {
212 return null;
213 }
214 }
215
216 /**
217 * A <code>Resource</code> represents a resource in some
218 * <code>URLLoader</code>. It also contains all information (e.g.,
219 * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and
220 * <code>InputStream</code>) that is necessary for loading resources
221 * and creating classes from a <code>URL</code>.
222 */
223 static abstract class Resource
224 {
225 final URLLoader loader;
226 final String name;
227
228 Resource(URLLoader loader, String name)
229 {
230 this.loader = loader;
231 this.name = name;
232 }
233
234 /**
235 * Returns the non-null <code>CodeSource</code> associated with
236 * this resource.
237 */
238 CodeSource getCodeSource()
239 {
240 Certificate[] certs = getCertificates();
241 if (certs == null)
242 return loader.noCertCodeSource;
243 else
244 return new CodeSource(loader.baseURL, certs);
245 }
246
247 /**
248 * Returns <code>Certificates</code> associated with this
249 * resource, or null when there are none.
250 */
251 Certificate[] getCertificates()
252 {
253 return null;
254 }
255
256 /**
257 * Return a <code>URL</code> that can be used to access this resource.
258 */
259 abstract URL getURL();
260
261 /**
262 * Returns the size of this <code>Resource</code> in bytes or
263 * <code>-1</code> when unknown.
264 */
265 abstract int getLength();
266
267 /**
268 * Returns the non-null <code>InputStream</code> through which
269 * this resource can be loaded.
270 */
271 abstract InputStream getInputStream() throws IOException;
272 }
273
274 /**
275 * A <code>JarURLLoader</code> is a type of <code>URLLoader</code>
276 * only loading from jar url.
277 */
278 final static class JarURLLoader extends URLLoader
279 {
280 final JarFile jarfile; // The jar file for this url
281 final URL baseJarURL; // Base jar: url for all resources loaded from jar
282
283 public JarURLLoader(URLClassLoader classloader, URL baseURL)
284 {
285 super(classloader, baseURL);
286
287 // cache url prefix for all resources in this jar url
288 String external = baseURL.toExternalForm();
289 StringBuffer sb = new StringBuffer(external.length() + 6);
290 sb.append("jar:");
291 sb.append(external);
292 sb.append("!/");
293 String jarURL = sb.toString();
294
295 URL baseJarURL = null;
296 JarFile jarfile = null;
297 try
298 {
299 baseJarURL
300 = new URL(null, jarURL, classloader.getURLStreamHandler("jar"));
301 jarfile
302 = ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
303 }
304 catch (IOException ioe) { /* ignored */ }
305
306 this.baseJarURL = baseJarURL;
307 this.jarfile = jarfile;
308 }
309
310 /** get resource with the name "name" in the jar url */
311 Resource getResource(String name)
312 {
313 if (jarfile == null)
314 return null;
315
316 JarEntry je = jarfile.getJarEntry(name);
317 if(je != null)
318 return new JarURLResource(this, name, je);
319 else
320 return null;
321 }
322
323 Manifest getManifest()
324 {
325 try
326 {
327 return (jarfile == null) ? null : jarfile.getManifest();
328 }
329 catch (IOException ioe)
330 {
331 return null;
332 }
333 }
334 }
335
336 final static class JarURLResource extends Resource
337 {
338 private final JarEntry entry;
339
340 JarURLResource(JarURLLoader loader, String name, JarEntry entry)
341 {
342 super(loader, name);
343 this.entry = entry;
344 }
345
346 InputStream getInputStream() throws IOException
347 {
348 return ((JarURLLoader)loader).jarfile.getInputStream(entry);
349 }
350
351 int getLength()
352 {
353 return (int)entry.getSize();
354 }
355
356 Certificate[] getCertificates()
357 {
358 return entry.getCertificates();
359 }
360
361 URL getURL()
362 {
363 try
364 {
365 return new URL(((JarURLLoader)loader).baseJarURL, name,
366 loader.classloader.getURLStreamHandler("jar"));
367 }
368 catch(MalformedURLException e)
369 {
370 InternalError ie = new InternalError();
371 ie.initCause(e);
372 throw ie;
373 }
374 }
375 }
376
377 /**
378 * Loader for remote directories.
379 */
380 final static class RemoteURLLoader extends URLLoader
381 {
382 final private String protocol;
383
384 RemoteURLLoader(URLClassLoader classloader, URL url)
385 {
386 super(classloader, url);
387 protocol = url.getProtocol();
388 }
389
390 /**
391 * Get a remote resource.
392 * Returns null if no such resource exists.
393 */
394 Resource getResource(String name)
395 {
396 try
397 {
398 URL url = new URL(baseURL, name,
399 classloader.getURLStreamHandler(protocol));
400 URLConnection connection = url.openConnection();
401
402 // Open the connection and check the stream
403 // just to be sure it exists.
404 int length = connection.getContentLength();
405 InputStream stream = connection.getInputStream();
406
407 // We can do some extra checking if it is a http request
408 if (connection instanceof HttpURLConnection)
409 {
410 int response
411 = ((HttpURLConnection)connection).getResponseCode();
412 if (response/100 != 2)
413 return null;
414 }
415
416 if (stream != null)
417 return new RemoteResource(this, name, url, stream, length);
418 else
419 return null;
420 }
421 catch (IOException ioe)
422 {
423 return null;
424 }
425 }
426 }
427
428 /**
429 * A resource from some remote location.
430 */
431 final static class RemoteResource extends Resource
432 {
433 final private URL url;
434 final private InputStream stream;
435 final private int length;
436
437 RemoteResource(RemoteURLLoader loader, String name, URL url,
438 InputStream stream, int length)
439 {
440 super(loader, name);
441 this.url = url;
442 this.stream = stream;
443 this.length = length;
444 }
445
446 InputStream getInputStream() throws IOException
447 {
448 return stream;
449 }
450
451 public int getLength()
452 {
453 return length;
454 }
455
456 public URL getURL()
457 {
458 return url;
459 }
460 }
461
462 /**
463 * A <code>FileURLLoader</code> is a type of <code>URLLoader</code>
464 * only loading from file url.
465 */
466 final static class FileURLLoader extends URLLoader
467 {
468 File dir; //the file for this file url
469
470 FileURLLoader(URLClassLoader classloader, URL url)
471 {
472 super(classloader, url);
473 dir = new File(baseURL.getFile());
474 }
475
476 /** get resource with the name "name" in the file url */
477 Resource getResource(String name)
478 {
479 File file = new File(dir, name);
480 if (file.exists() && !file.isDirectory())
481 return new FileResource(this, name, file);
482 return null;
483 }
484 }
485
486 final static class FileResource extends Resource
487 {
488 final File file;
489
490 FileResource(FileURLLoader loader, String name, File file)
491 {
492 super(loader, name);
493 this.file = file;
494 }
495
496 InputStream getInputStream() throws IOException
497 {
498 return new FileInputStream(file);
499 }
500
501 public int getLength()
502 {
503 return (int)file.length();
504 }
505
506 public URL getURL()
507 {
508 try
509 {
510 return new URL(loader.baseURL, name,
511 loader.classloader.getURLStreamHandler("file"));
512 }
513 catch(MalformedURLException e)
514 {
515 InternalError ie = new InternalError();
516 ie.initCause(e);
517 throw ie;
518 }
519 }
520 }
521
522 // Constructors
523
524 /**
525 * Creates a URLClassLoader that gets classes from the supplied URLs.
526 * To determine if this classloader may be created the constructor of
527 * the super class (<code>SecureClassLoader</code>) is called first, which
528 * can throw a SecurityException. Then the supplied URLs are added
529 * in the order given to the URLClassLoader which uses these URLs to
530 * load classes and resources (after using the default parent ClassLoader).
531 *
532 * @exception SecurityException if the SecurityManager disallows the
533 * creation of a ClassLoader.
534 * @param urls Locations that should be searched by this ClassLoader when
535 * resolving Classes or Resources.
536 * @see SecureClassLoader
537 */
538 public URLClassLoader(URL[] urls) throws SecurityException
539 {
540 super();
541 this.factory = null;
542 this.securityContext = null;
543 addURLs(urls);
544 }
545
546 /**
547 * Private constructor used by the static
548 * <code>newInstance(URL[])</code> method. Creates an
549 * <code>URLClassLoader</code> without any <code>URL</code>s
550 * yet. This is used to bypass the normal security check for
551 * creating classloaders, but remembers the security context which
552 * will be used when defining classes. The <code>URL</code>s to
553 * load from must be added by the <code>newInstance()</code> method
554 * in the security context of the caller.
555 *
556 * @param securityContext the security context of the unprivileged code.
557 */
558 private URLClassLoader(AccessControlContext securityContext)
559 {
560 super();
561 this.factory = null;
562 this.securityContext = securityContext;
563 }
564
565 /**
566 * Creates a <code>URLClassLoader</code> that gets classes from the supplied
567 * <code>URL</code>s.
568 * To determine if this classloader may be created the constructor of
569 * the super class (<code>SecureClassLoader</code>) is called first, which
570 * can throw a SecurityException. Then the supplied URLs are added
571 * in the order given to the URLClassLoader which uses these URLs to
572 * load classes and resources (after using the supplied parent ClassLoader).
573 * @exception SecurityException if the SecurityManager disallows the
574 * creation of a ClassLoader.
575 * @exception SecurityException
576 * @param urls Locations that should be searched by this ClassLoader when
577 * resolving Classes or Resources.
578 * @param parent The parent class loader used before trying this class
579 * loader.
580 * @see SecureClassLoader
581 */
582 public URLClassLoader(URL[] urls, ClassLoader parent)
583 throws SecurityException
584 {
585 super(parent);
586 this.factory = null;
587 this.securityContext = null;
588 addURLs(urls);
589 }
590
591 /**
592 * Private constructor used by the static
593 * <code>newInstance(URL[])</code> method. Creates an
594 * <code>URLClassLoader</code> with the given parent but without any
595 * <code>URL</code>s yet. This is used to bypass the normal security
596 * check for creating classloaders, but remembers the security
597 * context which will be used when defining classes. The
598 * <code>URL</code>s to load from must be added by the
599 * <code>newInstance()</code> method in the security context of the
600 * caller.
601 *
602 * @param securityContext the security context of the unprivileged code.
603 */
604 private URLClassLoader(ClassLoader parent,
605 AccessControlContext securityContext)
606 {
607 super(parent);
608 this.factory = null;
609 this.securityContext = securityContext;
610 }
611
612 /**
613 * Creates a URLClassLoader that gets classes from the supplied URLs.
614 * To determine if this classloader may be created the constructor of
615 * the super class (<CODE>SecureClassLoader</CODE>) is called first, which
616 * can throw a SecurityException. Then the supplied URLs are added
617 * in the order given to the URLClassLoader which uses these URLs to
618 * load classes and resources (after using the supplied parent ClassLoader).
619 * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the
620 * protocol handlers of the supplied URLs.
621 * @exception SecurityException if the SecurityManager disallows the
622 * creation of a ClassLoader.
623 * @exception SecurityException
624 * @param urls Locations that should be searched by this ClassLoader when
625 * resolving Classes or Resources.
626 * @param parent The parent class loader used before trying this class
627 * loader.
628 * @param factory Used to get the protocol handler for the URLs.
629 * @see SecureClassLoader
630 */
631 public URLClassLoader(URL[] urls,
632 ClassLoader parent,
633 URLStreamHandlerFactory factory)
634 throws SecurityException
635 {
636 super(parent);
637 this.securityContext = null;
638 this.factory = factory;
639 addURLs(urls);
640
641 // If this factory is still not in factoryCache, add it,
642 // since we only support three protocols so far, 5 is enough
643 // for cache initial size
644 synchronized(factoryCache)
645 {
646 if(factory != null && factoryCache.get(factory) == null)
647 factoryCache.put(factory, new HashMap(5));
648 }
649 }
650
651 // Methods
652
653 /**
654 * Adds a new location to the end of the internal URL store.
655 * @param newUrl the location to add
656 */
657 protected void addURL(URL newUrl)
658 {
659 synchronized(urlloaders)
660 {
661 if (newUrl == null)
662 return; // Silently ignore...
663
664 // check global cache to see if there're already url loader
665 // for this url
666 URLLoader loader = (URLLoader)urlloaders.get(newUrl);
667 if (loader == null)
668 {
669 String file = newUrl.getFile();
670 // Check that it is not a directory
671 if (! (file.endsWith("/") || file.endsWith(File.separator)))
672 loader = new JarURLLoader(this, newUrl);
673 else if ("file".equals(newUrl.getProtocol()))
674 loader = new FileURLLoader(this, newUrl);
675 else
676 loader = new RemoteURLLoader(this, newUrl);
677
678 // cache it
679 urlloaders.put(newUrl, loader);
680 }
681
682 urls.add(newUrl);
683 urlinfos.add(loader);
684 }
685 }
686
687 /**
688 * Adds an array of new locations to the end of the internal URL store.
689 * @param newUrls the locations to add
690 */
691 private void addURLs(URL[] newUrls)
692 {
693 for (int i = 0; i < newUrls.length; i++)
694 {
695 addURL(newUrls[i]);
696 }
697 }
698
699 /**
700 * Defines a Package based on the given name and the supplied manifest
701 * information. The manifest indicates the tile, version and
702 * vendor information of the specification and implementation and wheter the
703 * package is sealed. If the Manifest indicates that the package is sealed
704 * then the Package will be sealed with respect to the supplied URL.
705 *
706 * @exception IllegalArgumentException If this package name already exists
707 * in this class loader
708 * @param name The name of the package
709 * @param manifest The manifest describing the specification,
710 * implementation and sealing details of the package
711 * @param url the code source url to seal the package
712 * @return the defined Package
713 */
714 protected Package definePackage(String name, Manifest manifest, URL url)
715 throws IllegalArgumentException
716 {
717 Attributes attr = manifest.getMainAttributes();
718 String specTitle =
719 attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
720 String specVersion =
721 attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
722 String specVendor =
723 attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
724 String implTitle =
725 attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
726 String implVersion =
727 attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
728 String implVendor =
729 attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
730
731 // Look if the Manifest indicates that this package is sealed
732 // XXX - most likely not completely correct!
733 // Shouldn't we also check the sealed attribute of the complete jar?
734 // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled
735 // But how do we get that jar manifest here?
736 String sealed = attr.getValue(Attributes.Name.SEALED);
737 if ("false".equals(sealed))
738 {
739 // make sure that the URL is null so the package is not sealed
740 url = null;
741 }
742
743 return definePackage(name, specTitle, specVersion, specVendor,
744 implTitle, implVersion, implVendor, url);
745 }
746
747 /**
748 * Finds (the first) class by name from one of the locations. The locations
749 * are searched in the order they were added to the URLClassLoader.
750 *
751 * @param className the classname to find
752 * @exception ClassNotFoundException when the class could not be found or
753 * loaded
754 * @return a Class object representing the found class
755 */
756 protected Class findClass(final String className)
757 throws ClassNotFoundException
758 {
759 // Just try to find the resource by the (almost) same name
760 String resourceName = className.replace('.', '/') + ".class";
761 Resource resource = findURLResource(resourceName);
762 if (resource == null)
763 throw new ClassNotFoundException(className + " not found in " + urls);
764
765 // Try to read the class data, create the CodeSource, Package and
766 // construct the class (and watch out for those nasty IOExceptions)
767 try
768 {
769 byte [] data;
770 InputStream in = resource.getInputStream();
771 int length = resource.getLength();
772 if (length != -1)
773 {
774 // We know the length of the data.
775 // Just try to read it in all at once
776 data = new byte[length];
777 int pos = 0;
778 while(length - pos > 0)
779 {
780 int len = in.read(data, pos, length - pos);
781 if (len == -1)
782 throw new EOFException("Not enough data reading from: "
783 + in);
784 pos += len;
785 }
786 }
787 else
788 {
789 // We don't know the data length.
790 // Have to read it in chunks.
791 ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
792 byte b[] = new byte[4096];
793 int l = 0;
794 while (l != -1)
795 {
796 l = in.read(b);
797 if (l != -1)
798 out.write(b, 0, l);
799 }
800 data = out.toByteArray();
801 }
802 final byte[] classData = data;
803
804 // Now get the CodeSource
805 final CodeSource source = resource.getCodeSource();
806
807 // Find out package name
808 String packageName = null;
809 int lastDot = className.lastIndexOf('.');
810 if (lastDot != -1)
811 packageName = className.substring(0, lastDot);
812
813 if (packageName != null && getPackage(packageName) == null)
814 {
815 // define the package
816 Manifest manifest = resource.loader.getManifest();
817 if (manifest == null)
818 definePackage(packageName,
819 null, null, null, null, null, null, null);
820 else
821 definePackage(packageName, manifest, resource.loader.baseURL);
822 }
823
824 // And finally construct the class!
825 SecurityManager sm = System.getSecurityManager();
826 if (sm != null && securityContext != null)
827 {
828 return (Class)AccessController.doPrivileged
829 (new PrivilegedAction()
830 {
831 public Object run()
832 {
833 return defineClass(className, classData,
834 0, classData.length,
835 source);
836 }
837 }, securityContext);
838 }
839 else
840 return defineClass(className, classData,
841 0, classData.length,
842 source);
843 }
844 catch (IOException ioe)
845 {
846 throw new ClassNotFoundException(className, ioe);
847 }
848 }
849
850 /**
851 * Finds the first occurrence of a resource that can be found. The locations
852 * are searched in the order they were added to the URLClassLoader.
853 *
854 * @param resourceName the resource name to look for
855 * @return the URLResource for the resource if found, null otherwise
856 */
857 private Resource findURLResource(String resourceName)
858 {
859 int max = urls.size();
860 for (int i = 0; i < max; i++)
861 {
862 URLLoader loader = (URLLoader)urlinfos.elementAt(i);
863 if (loader == null)
864 continue;
865
866 Resource resource = loader.getResource(resourceName);
867 if (resource != null)
868 return resource;
869 }
870 return null;
871 }
872
873 /**
874 * Finds the first occurrence of a resource that can be found.
875 *
876 * @param resourceName the resource name to look for
877 * @return the URL if found, null otherwise
878 */
879 public URL findResource(String resourceName)
880 {
881 Resource resource = findURLResource(resourceName);
882 if (resource != null)
883 return resource.getURL();
884
885 // Resource not found
886 return null;
887 }
888
889 /**
890 * If the URLStreamHandlerFactory has been set this return the appropriate
891 * URLStreamHandler for the given protocol, if not set returns null.
892 *
893 * @param protocol the protocol for which we need a URLStreamHandler
894 * @return the appropriate URLStreamHandler or null
895 */
896 URLStreamHandler getURLStreamHandler(String protocol)
897 {
898 if (factory == null)
899 return null;
900
901 URLStreamHandler handler;
902 synchronized (factoryCache)
903 {
904 // check if there're handler for the same protocol in cache
905 HashMap cache = (HashMap)factoryCache.get(factory);
906 handler = (URLStreamHandler)cache.get(protocol);
907 if(handler == null)
908 {
909 // add it to cache
910 handler = factory.createURLStreamHandler(protocol);
911 cache.put(protocol, handler);
912 }
913 }
914 return handler;
915 }
916
917 /**
918 * Finds all the resources with a particular name from all the locations.
919 *
920 * @exception IOException when an error occurs accessing one of the
921 * locations
922 * @param resourceName the name of the resource to lookup
923 * @return a (possible empty) enumeration of URLs where the resource can be
924 * found
925 */
926 public Enumeration findResources(String resourceName) throws IOException
927 {
928 Vector resources = new Vector();
929 int max = urls.size();
930 for (int i = 0; i < max; i++)
931 {
932 URLLoader loader = (URLLoader)urlinfos.elementAt(i);
933 Resource resource = loader.getResource(resourceName);
934 if (resource != null)
935 resources.add(resource.getURL());
936 }
937 return resources.elements();
938 }
939
940 /**
941 * Returns the permissions needed to access a particular code
942 * source. These permissions includes those returned by
943 * <code>SecureClassLoader.getPermissions()</code> and the actual
944 * permissions to access the objects referenced by the URL of the
945 * code source. The extra permissions added depend on the protocol
946 * and file portion of the URL in the code source. If the URL has
947 * the "file" protocol ends with a '/' character then it must be a
948 * directory and a file Permission to read everything in that
949 * directory and all subdirectories is added. If the URL had the
950 * "file" protocol and doesn't end with a '/' character then it must
951 * be a normal file and a file permission to read that file is
952 * added. If the <code>URL</code> has any other protocol then a
953 * socket permission to connect and accept connections from the host
954 * portion of the URL is added.
955 *
956 * @param source The codesource that needs the permissions to be accessed
957 * @return the collection of permissions needed to access the code resource
958 * @see java.security.SecureClassLoader#getPermissions()
959 */
960 protected PermissionCollection getPermissions(CodeSource source)
961 {
962 // XXX - This implementation does exactly as the Javadoc describes.
963 // But maybe we should/could use URLConnection.getPermissions()?
964
965 // First get the permissions that would normally be granted
966 PermissionCollection permissions = super.getPermissions(source);
967
968 // Now add the any extra permissions depending on the URL location
969 URL url = source.getLocation();
970 String protocol = url.getProtocol();
971 if (protocol.equals("file"))
972 {
973 String file = url.getFile();
974 // If the file end in / it must be an directory
975 if (file.endsWith("/") || file.endsWith(File.separator))
976 {
977 // Grant permission to read everything in that directory and
978 // all subdirectories
979 permissions.add(new FilePermission(file + "-", "read"));
980 }
981 else
982 {
983 // It is a 'normal' file
984 // Grant permission to access that file
985 permissions.add(new FilePermission(file, "read"));
986 }
987 }
988 else
989 {
990 // Grant permission to connect to and accept connections from host
991 String host = url.getHost();
992 if (host != null)
993 permissions.add(new SocketPermission(host, "connect,accept"));
994 }
995
996 return permissions;
997 }
998
999 /**
1000 * Returns all the locations that this class loader currently uses the
1001 * resolve classes and resource. This includes both the initially supplied
1002 * URLs as any URLs added later by the loader.
1003 * @return All the currently used URLs
1004 */
1005 public URL[] getURLs()
1006 {
1007 return (URL[]) urls.toArray(new URL[urls.size()]);
1008 }
1009
1010 /**
1011 * Creates a new instance of a <code>URLClassLoader</code> that gets
1012 * classes from the supplied <code>URL</code>s. This class loader
1013 * will have as parent the standard system class loader.
1014 *
1015 * @param urls the initial URLs used to resolve classes and
1016 * resources
1017 *
1018 * @exception SecurityException when the calling code does not have
1019 * permission to access the given <code>URL</code>s
1020 */
1021 public static URLClassLoader newInstance(URL urls[])
1022 throws SecurityException
1023 {
1024 return newInstance(urls, null);
1025 }
1026
1027 /**
1028 * Creates a new instance of a <code>URLClassLoader</code> that gets
1029 * classes from the supplied <code>URL</code>s and with the supplied
1030 * loader as parent class loader.
1031 *
1032 * @param urls the initial URLs used to resolve classes and
1033 * resources
1034 * @param parent the parent class loader
1035 *
1036 * @exception SecurityException when the calling code does not have
1037 * permission to access the given <code>URL</code>s
1038 */
1039 public static URLClassLoader newInstance(URL urls[],
1040 final ClassLoader parent)
1041 throws SecurityException
1042 {
1043 SecurityManager sm = System.getSecurityManager();
1044 if (sm == null)
1045 return new URLClassLoader(urls, parent);
1046 else
1047 {
1048 final Object securityContext = sm.getSecurityContext();
1049 // XXX - What to do with anything else then an AccessControlContext?
1050 if (!(securityContext instanceof AccessControlContext))
1051 throw new SecurityException
1052 ("securityContext must be AccessControlContext: "
1053 + securityContext);
1054
1055 URLClassLoader loader =
1056 (URLClassLoader)AccessController.doPrivileged(new PrivilegedAction()
1057 {
1058 public Object run()
1059 {
1060 return new URLClassLoader
1061 (parent, (AccessControlContext)securityContext);
1062 }
1063 });
1064 loader.addURLs(urls);
1065 return loader;
1066 }
1067 }
1068}
Note: See TracBrowser for help on using the repository browser.