- Timestamp:
- Apr 27, 2004, 8:39:34 PM (22 years ago)
- Location:
- branches/GNU/src/gcc
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
libjava/java/net/URLClassLoader.java (modified) (1 diff, 1 prop)
Legend:
- Unmodified
- Added
- Removed
-
branches/GNU/src/gcc
- Property svn:ignore
-
old new 26 26 configure.vr 27 27 configure.vrs 28 28 29 Makefile 29 dir.info30 30 lost+found 31 31 update.out
-
- Property svn:ignore
-
branches/GNU/src/gcc/libjava/java/net/URLClassLoader.java
-
Property cvs2svn:cvs-rev
changed from
1.1to1.1.1.2
r1390 r1391 1 /* Copyright (C) 1999, 2000 Free Software Foundation 2 3 This file is part of libgcj. 4 5 This software is copyrighted work licensed under the terms of the 6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for 7 details. */ 1 /* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs 2 Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19 02111-1307 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 8 37 9 38 package java.net; 10 39 11 import java.io.*; 12 import java.util.jar.*; 40 import java.io.ByteArrayOutputStream; 41 import java.io.EOFException; 42 import java.io.File; 43 import java.io.FileInputStream; 44 import java.io.FileNotFoundException; 45 import java.io.FilterInputStream; 46 import java.io.FilePermission; 47 import java.io.InputStream; 48 import java.io.IOException; 49 import java.security.AccessController; 50 import java.security.AccessControlContext; 51 import java.security.CodeSource; 52 import java.security.SecureClassLoader; 53 import java.security.PrivilegedAction; 54 import java.security.PermissionCollection; 55 import java.security.cert.Certificate; 13 56 import java.util.Enumeration; 14 57 import java.util.Vector; 15 16 public class URLClassLoader extends ClassLoader 58 import java.util.HashMap; 59 import java.util.jar.Attributes; 60 import java.util.jar.JarEntry; 61 import java.util.jar.JarFile; 62 import java.util.jar.Manifest; 63 import 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 ([email protected]) 120 * @author Wu Gansha ([email protected]) 121 */ 122 123 public class URLClassLoader extends SecureClassLoader 17 124 { 18 // The URLStreamHandlerFactory 19 URLStreamHandlerFactory factory = null; 20 21 // `path' contains simply the URL's we're using for the searching. 22 private Vector path; 23 24 // If path[n] is a zip/jar, then this holds a JarURLConnection for 25 // that thing, otherwise, path[n] is null. 26 private Vector info; 27 28 private URLStreamHandler getHandler0 (String protocol) 29 { 30 if (factory != null) 31 return factory.createURLStreamHandler(protocol); 32 else 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 { 33 212 return null; 34 } 35 36 public URLClassLoader (URL[] urls) 37 { 38 this (urls, null, null); 39 } 40 41 public URLClassLoader (URL[] urls, ClassLoader parent) 42 { 43 this (urls, parent, null); 44 } 45 46 // A File URL may actually be a Jar URL. Convert if possible. 47 private URL jarFileize (URL url) 48 { 49 if (! url.getProtocol ().equals ("jar")) 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) 50 645 { 51 String f = url.getFile (); 52 53 // If it ends with '/' we'll take it for a directory, 54 // otherwise it's a jar file. This is how JDK 1.2 defines 55 // it, so we will not try to be smart here. 56 if (f.charAt (f.length ()-1) != '/') 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) 57 668 { 58 try 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) 59 779 { 60 url = new URL ("jar", "", -1, (url.toExternalForm ())+"!/", 61 getHandler0 ("jar")); 62 } 63 catch (MalformedURLException x) 64 { 65 /* ignore */ 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; 66 785 } 67 }68 }69 return url;70 }71 72 protected void addURL (URL url)73 {74 JarURLConnection conn = null;75 76 // Convert a Jar File URL into Jar URL if possible.77 url = jarFileize (url);78 79 path.addElement (url);80 81 if (url.getProtocol ().equals ("jar"))82 {83 try84 {85 conn = (JarURLConnection) url.openConnection ();86 }87 catch (java.io.IOException x)88 {89 /* ignore */90 }91 }92 93 info.addElement (conn);94 }95 96 public URLClassLoader (URL[] urls, ClassLoader parent,97 URLStreamHandlerFactory fac)98 {99 super (parent);100 101 factory = fac;102 103 if (urls == null || urls.length == 0)104 {105 path = new Vector (1);106 info = new Vector (1);107 return;108 }109 110 path = new Vector (urls.length);111 info = new Vector (urls.length);112 113 for (int i = 0; i < urls.length; i++)114 {115 // Convert a Jar File URL into a Jar URL is possible.116 URL u = jarFileize(urls[i]);117 118 path.addElement (u);119 120 if (u.getProtocol ().equals ("jar"))121 {122 JarURLConnection conn = null;123 try124 {125 conn = (JarURLConnection) u.openConnection ();126 }127 catch (java.io.IOException x)128 {129 /* ignore */130 }131 info.addElement (conn);132 786 } 133 787 else 134 788 { 135 info.addElement (null); 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); 136 912 } 137 913 } 138 } 139 140 public URL[] getURLs () 141 { 142 URL[] urls = new URL[path.size()]; 143 path.copyInto (urls); 144 return urls; 145 } 146 147 public Enumeration findResources (String name) 148 { 149 Vector results = new Vector (); 150 151 for (int i = 0; i < path.size(); i++) 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++) 152 931 { 153 URL u = (URL)path.elementAt (i); 154 155 try { 156 JarURLConnection conn = (JarURLConnection) info.elementAt (i); 157 158 if (conn != null) 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() 159 1057 { 160 if (conn.getJarFile().getJarEntry (name) != null) 161 results.addElement (new URL(u, name, getHandler0 (u.getProtocol()))); 162 } 163 else 164 { 165 URL p = new URL (u, name, getHandler0 (u.getProtocol())); 166 167 InputStream is = p.openStream(); 168 if (is != null) 169 { 170 is.close(); 171 results.addElement (p); 172 } 173 } 174 175 // if we get an exception ... try the next path element 176 } catch (IOException x) { 177 continue; 178 } 1058 public Object run() 1059 { 1060 return new URLClassLoader 1061 (parent, (AccessControlContext)securityContext); 1062 } 1063 }); 1064 loader.addURLs(urls); 1065 return loader; 179 1066 } 180 181 return results.elements ();182 }183 184 public URL findResource (String name)185 {186 for (int i = 0; i < path.size(); i++)187 {188 URL u = (URL)path.elementAt (i);189 190 try {191 JarURLConnection conn = (JarURLConnection) info.elementAt (i);192 193 if (conn != null)194 {195 if (conn.getJarFile().getJarEntry (name) != null)196 return new URL(u, name, getHandler0 (u.getProtocol()));197 }198 else199 {200 URL p = new URL (u, name, getHandler0 (u.getProtocol()));201 202 InputStream is = p.openStream();203 if (is != null)204 {205 is.close();206 return p;207 }208 }209 210 // if we get an exception ... try the next path element211 } catch (IOException x) {212 continue;213 }214 }215 216 return null;217 }218 219 // and finally, we can implement our class loader functionality.220 protected Class findClass (String name)221 throws ClassNotFoundException222 {223 if (name == null)224 throw new ClassNotFoundException ("null");225 226 try227 {228 URL u = getResource (name.replace ('.', '/') + ".class");229 230 if (u == null)231 throw new ClassNotFoundException (name);232 233 URLConnection connection = u.openConnection ();234 InputStream is = connection.getInputStream ();235 236 int len = connection.getContentLength ();237 byte[] data = new byte[len];238 239 int left = len;240 int off = 0;241 while (left > 0)242 {243 int c = is.read (data, off, len-off);244 if (c == -1 || c == 0)245 throw new InternalError ("premature end of file");246 left -= c;247 off += c;248 }249 250 return defineClass (name, data, 0, len);251 }252 catch (java.io.IOException x)253 {254 throw new ClassNotFoundException(name);255 }256 1067 } 257 1068 } 258 -
Property cvs2svn:cvs-rev
changed from
Note:
See TracChangeset
for help on using the changeset viewer.
