1 /* 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.net; 27 28 import java.lang.reflect.Method; 29 import java.lang.reflect.Modifier; 30 import java.lang.ref.*; 31 import java.io.*; 32 import java.net.URL; 33 import java.net.URLConnection; 34 import java.net.URLStreamHandlerFactory; 35 import java.util.Enumeration; 36 import java.util.*; 37 import java.util.jar.Manifest; 38 import java.util.jar.JarFile; 39 import java.util.jar.Attributes; 40 import java.util.jar.Attributes.Name; 41 import java.security.CodeSigner; 42 import java.security.PrivilegedAction; 43 import java.security.PrivilegedExceptionAction; 44 import java.security.AccessController; 45 import java.security.AccessControlContext; 46 import java.security.SecureClassLoader; 47 import java.security.CodeSource; 48 import java.security.Permission; 49 import java.security.PermissionCollection; 50 import sun.misc.Resource; 51 import sun.misc.URLClassPath; 52 import sun.net.www.ParseUtil; 53 import sun.security.util.SecurityConstants; 54 55 /** 56 * This class loader is used to load classes and resources from a search 57 * path of URLs referring to both JAR files and directories. Any URL that 58 * ends with a '/' is assumed to refer to a directory. Otherwise, the URL 59 * is assumed to refer to a JAR file which will be opened as needed. 60 * <p> 61 * The AccessControlContext of the thread that created the instance of 62 * URLClassLoader will be used when subsequently loading classes and 63 * resources. 64 * <p> 65 * The classes that are loaded are by default granted permission only to 66 * access the URLs specified when the URLClassLoader was created. 67 * 68 * @author David Connelly 69 * @since 1.2 70 */ 71 public class URLClassLoader extends SecureClassLoader implements Closeable { 72 /* The search path for classes and resources */ 73 private final URLClassPath ucp; 74 75 /* The context to be used when loading classes and resources */ 76 private final AccessControlContext acc; 77 78 /** 79 * Constructs a new URLClassLoader for the given URLs. The URLs will be 80 * searched in the order specified for classes and resources after first 81 * searching in the specified parent class loader. Any URL that ends with 82 * a '/' is assumed to refer to a directory. Otherwise, the URL is assumed 83 * to refer to a JAR file which will be downloaded and opened as needed. 84 * 85 * <p>If there is a security manager, this method first 86 * calls the security manager's {@code checkCreateClassLoader} method 87 * to ensure creation of a class loader is allowed. 88 * 89 * @param urls the URLs from which to load classes and resources 90 * @param parent the parent class loader for delegation 91 * @exception SecurityException if a security manager exists and its 92 * {@code checkCreateClassLoader} method doesn't allow 93 * creation of a class loader. 94 * @see SecurityManager#checkCreateClassLoader 95 */ URLClassLoader(URL[] urls, ClassLoader parent)96 public URLClassLoader(URL[] urls, ClassLoader parent) { 97 super(parent); 98 // this is to make the stack depth consistent with 1.1 99 SecurityManager security = System.getSecurityManager(); 100 if (security != null) { 101 security.checkCreateClassLoader(); 102 } 103 ucp = new URLClassPath(urls); 104 this.acc = AccessController.getContext(); 105 } 106 URLClassLoader(URL[] urls, ClassLoader parent, AccessControlContext acc)107 URLClassLoader(URL[] urls, ClassLoader parent, 108 AccessControlContext acc) { 109 super(parent); 110 // this is to make the stack depth consistent with 1.1 111 SecurityManager security = System.getSecurityManager(); 112 if (security != null) { 113 security.checkCreateClassLoader(); 114 } 115 ucp = new URLClassPath(urls); 116 this.acc = acc; 117 } 118 119 /** 120 * Constructs a new URLClassLoader for the specified URLs using the 121 * default delegation parent <code>ClassLoader</code>. The URLs will 122 * be searched in the order specified for classes and resources after 123 * first searching in the parent class loader. Any URL that ends with 124 * a '/' is assumed to refer to a directory. Otherwise, the URL is 125 * assumed to refer to a JAR file which will be downloaded and opened 126 * as needed. 127 * 128 * <p>If there is a security manager, this method first 129 * calls the security manager's <code>checkCreateClassLoader</code> method 130 * to ensure creation of a class loader is allowed. 131 * 132 * @param urls the URLs from which to load classes and resources 133 * 134 * @exception SecurityException if a security manager exists and its 135 * <code>checkCreateClassLoader</code> method doesn't allow 136 * creation of a class loader. 137 * @see SecurityManager#checkCreateClassLoader 138 */ URLClassLoader(URL[] urls)139 public URLClassLoader(URL[] urls) { 140 super(); 141 // this is to make the stack depth consistent with 1.1 142 SecurityManager security = System.getSecurityManager(); 143 if (security != null) { 144 security.checkCreateClassLoader(); 145 } 146 ucp = new URLClassPath(urls); 147 this.acc = AccessController.getContext(); 148 } 149 URLClassLoader(URL[] urls, AccessControlContext acc)150 URLClassLoader(URL[] urls, AccessControlContext acc) { 151 super(); 152 // this is to make the stack depth consistent with 1.1 153 SecurityManager security = System.getSecurityManager(); 154 if (security != null) { 155 security.checkCreateClassLoader(); 156 } 157 ucp = new URLClassPath(urls); 158 this.acc = acc; 159 } 160 161 /** 162 * Constructs a new URLClassLoader for the specified URLs, parent 163 * class loader, and URLStreamHandlerFactory. The parent argument 164 * will be used as the parent class loader for delegation. The 165 * factory argument will be used as the stream handler factory to 166 * obtain protocol handlers when creating new jar URLs. 167 * 168 * <p>If there is a security manager, this method first 169 * calls the security manager's <code>checkCreateClassLoader</code> method 170 * to ensure creation of a class loader is allowed. 171 * 172 * @param urls the URLs from which to load classes and resources 173 * @param parent the parent class loader for delegation 174 * @param factory the URLStreamHandlerFactory to use when creating URLs 175 * 176 * @exception SecurityException if a security manager exists and its 177 * <code>checkCreateClassLoader</code> method doesn't allow 178 * creation of a class loader. 179 * @see SecurityManager#checkCreateClassLoader 180 */ URLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory)181 public URLClassLoader(URL[] urls, ClassLoader parent, 182 URLStreamHandlerFactory factory) { 183 super(parent); 184 // this is to make the stack depth consistent with 1.1 185 SecurityManager security = System.getSecurityManager(); 186 if (security != null) { 187 security.checkCreateClassLoader(); 188 } 189 ucp = new URLClassPath(urls, factory); 190 acc = AccessController.getContext(); 191 } 192 193 /* A map (used as a set) to keep track of closeable local resources 194 * (either JarFiles or FileInputStreams). We don't care about 195 * Http resources since they don't need to be closed. 196 * 197 * If the resource is coming from a jar file 198 * we keep a (weak) reference to the JarFile object which can 199 * be closed if URLClassLoader.close() called. Due to jar file 200 * caching there will typically be only one JarFile object 201 * per underlying jar file. 202 * 203 * For file resources, which is probably a less common situation 204 * we have to keep a weak reference to each stream. 205 */ 206 207 private WeakHashMap<Closeable,Void> 208 closeables = new WeakHashMap<>(); 209 210 /** 211 * Returns an input stream for reading the specified resource. 212 * If this loader is closed, then any resources opened by this method 213 * will be closed. 214 * 215 * <p> The search order is described in the documentation for {@link 216 * #getResource(String)}. </p> 217 * 218 * @param name 219 * The resource name 220 * 221 * @return An input stream for reading the resource, or <tt>null</tt> 222 * if the resource could not be found 223 * 224 * @since 1.7 225 */ getResourceAsStream(String name)226 public InputStream getResourceAsStream(String name) { 227 URL url = getResource(name); 228 try { 229 if (url == null) { 230 return null; 231 } 232 URLConnection urlc = url.openConnection(); 233 InputStream is = urlc.getInputStream(); 234 if (urlc instanceof JarURLConnection) { 235 JarURLConnection juc = (JarURLConnection)urlc; 236 JarFile jar = juc.getJarFile(); 237 synchronized (closeables) { 238 if (!closeables.containsKey(jar)) { 239 closeables.put(jar, null); 240 } 241 } 242 } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) { 243 synchronized (closeables) { 244 closeables.put(is, null); 245 } 246 } 247 return is; 248 } catch (IOException e) { 249 return null; 250 } 251 } 252 253 /** 254 * Closes this URLClassLoader, so that it can no longer be used to load 255 * new classes or resources that are defined by this loader. 256 * Classes and resources defined by any of this loader's parents in the 257 * delegation hierarchy are still accessible. Also, any classes or resources 258 * that are already loaded, are still accessible. 259 * <p> 260 * In the case of jar: and file: URLs, it also closes any files 261 * that were opened by it. If another thread is loading a 262 * class when the {@code close} method is invoked, then the result of 263 * that load is undefined. 264 * <p> 265 * The method makes a best effort attempt to close all opened files, 266 * by catching {@link IOException}s internally. Unchecked exceptions 267 * and errors are not caught. Calling close on an already closed 268 * loader has no effect. 269 * <p> 270 * @throws IOException if closing any file opened by this class loader 271 * resulted in an IOException. Any such exceptions are caught internally. 272 * If only one is caught, then it is re-thrown. If more than one exception 273 * is caught, then the second and following exceptions are added 274 * as suppressed exceptions of the first one caught, which is then re-thrown. 275 * 276 * @throws SecurityException if a security manager is set, and it denies 277 * {@link RuntimePermission}<tt>("closeClassLoader")</tt> 278 * 279 * @since 1.7 280 */ close()281 public void close() throws IOException { 282 SecurityManager security = System.getSecurityManager(); 283 if (security != null) { 284 security.checkPermission(new RuntimePermission("closeClassLoader")); 285 } 286 List<IOException> errors = ucp.closeLoaders(); 287 288 // now close any remaining streams. 289 290 synchronized (closeables) { 291 Set<Closeable> keys = closeables.keySet(); 292 for (Closeable c : keys) { 293 try { 294 c.close(); 295 } catch (IOException ioex) { 296 errors.add(ioex); 297 } 298 } 299 closeables.clear(); 300 } 301 302 if (errors.isEmpty()) { 303 return; 304 } 305 306 IOException firstex = errors.remove(0); 307 308 // Suppress any remaining exceptions 309 310 for (IOException error: errors) { 311 firstex.addSuppressed(error); 312 } 313 throw firstex; 314 } 315 316 /** 317 * Appends the specified URL to the list of URLs to search for 318 * classes and resources. 319 * <p> 320 * If the URL specified is <code>null</code> or is already in the 321 * list of URLs, or if this loader is closed, then invoking this 322 * method has no effect. 323 * 324 * @param url the URL to be added to the search path of URLs 325 */ addURL(URL url)326 protected void addURL(URL url) { 327 ucp.addURL(url); 328 } 329 330 /** 331 * Returns the search path of URLs for loading classes and resources. 332 * This includes the original list of URLs specified to the constructor, 333 * along with any URLs subsequently appended by the addURL() method. 334 * @return the search path of URLs for loading classes and resources. 335 */ getURLs()336 public URL[] getURLs() { 337 return ucp.getURLs(); 338 } 339 340 /** 341 * Finds and loads the class with the specified name from the URL search 342 * path. Any URLs referring to JAR files are loaded and opened as needed 343 * until the class is found. 344 * 345 * @param name the name of the class 346 * @return the resulting class 347 * @exception ClassNotFoundException if the class could not be found, 348 * or if the loader is closed. 349 */ findClass(final String name)350 protected Class<?> findClass(final String name) 351 throws ClassNotFoundException 352 { 353 try { 354 return AccessController.doPrivileged( 355 new PrivilegedExceptionAction<Class>() { 356 public Class run() throws ClassNotFoundException { 357 String path = name.replace('.', '/').concat(".class"); 358 Resource res = ucp.getResource(path, false); 359 if (res != null) { 360 try { 361 return defineClass(name, res); 362 } catch (IOException e) { 363 throw new ClassNotFoundException(name, e); 364 } 365 } else { 366 throw new ClassNotFoundException(name); 367 } 368 } 369 }, acc); 370 } catch (java.security.PrivilegedActionException pae) { 371 throw (ClassNotFoundException) pae.getException(); 372 } 373 } 374 375 /* 376 * Retrieve the package using the specified package name. 377 * If non-null, verify the package using the specified code 378 * source and manifest. 379 */ 380 private Package getAndVerifyPackage(String pkgname, 381 Manifest man, URL url) { 382 Package pkg = getPackage(pkgname); 383 if (pkg != null) { 384 // Package found, so check package sealing. 385 if (pkg.isSealed()) { 386 // Verify that code source URL is the same. 387 if (!pkg.isSealed(url)) { 388 throw new SecurityException( 389 "sealing violation: package " + pkgname + " is sealed"); 390 } 391 } else { 392 // Make sure we are not attempting to seal the package 393 // at this code source URL. 394 if ((man != null) && isSealed(pkgname, man)) { 395 throw new SecurityException( 396 "sealing violation: can't seal package " + pkgname + 397 ": already loaded"); 398 } 399 } 400 } 401 return pkg; 402 } 403 404 /* 405 * Defines a Class using the class bytes obtained from the specified 406 * Resource. The resulting Class must be resolved before it can be 407 * used. 408 */ 409 private Class defineClass(String name, Resource res) throws IOException { 410 long t0 = System.nanoTime(); 411 int i = name.lastIndexOf('.'); 412 URL url = res.getCodeSourceURL(); 413 if (i != -1) { 414 String pkgname = name.substring(0, i); 415 // Check if package already loaded. 416 Manifest man = res.getManifest(); 417 if (getAndVerifyPackage(pkgname, man, url) == null) { 418 try { 419 if (man != null) { 420 definePackage(pkgname, man, url); 421 } else { 422 definePackage(pkgname, null, null, null, null, null, null, null); 423 } 424 } catch (IllegalArgumentException iae) { 425 // parallel-capable class loaders: re-verify in case of a 426 // race condition 427 if (getAndVerifyPackage(pkgname, man, url) == null) { 428 // Should never happen 429 throw new AssertionError("Cannot find package " + 430 pkgname); 431 } 432 } 433 } 434 } 435 // Now read the class bytes and define the class 436 java.nio.ByteBuffer bb = res.getByteBuffer(); 437 if (bb != null) { 438 // Use (direct) ByteBuffer: 439 CodeSigner[] signers = res.getCodeSigners(); 440 CodeSource cs = new CodeSource(url, signers); 441 return defineClass(name, bb, cs); 442 } else { 443 byte[] b = res.getBytes(); 444 // must read certificates AFTER reading bytes. 445 CodeSigner[] signers = res.getCodeSigners(); 446 CodeSource cs = new CodeSource(url, signers); 447 return defineClass(name, b, 0, b.length, cs); 448 } 449 } 450 451 /** 452 * Defines a new package by name in this ClassLoader. The attributes 453 * contained in the specified Manifest will be used to obtain package 454 * version and sealing information. For sealed packages, the additional 455 * URL specifies the code source URL from which the package was loaded. 456 * 457 * @param name the package name 458 * @param man the Manifest containing package version and sealing 459 * information 460 * @param url the code source url for the package, or null if none 461 * @exception IllegalArgumentException if the package name duplicates 462 * an existing package either in this class loader or one 463 * of its ancestors 464 * @return the newly defined Package object 465 */ 466 protected Package definePackage(String name, Manifest man, URL url) 467 throws IllegalArgumentException 468 { 469 String path = name.replace('.', '/').concat("/"); 470 String specTitle = null, specVersion = null, specVendor = null; 471 String implTitle = null, implVersion = null, implVendor = null; 472 String sealed = null; 473 URL sealBase = null; 474 475 Attributes attr = man.getAttributes(path); 476 if (attr != null) { 477 specTitle = attr.getValue(Name.SPECIFICATION_TITLE); 478 specVersion = attr.getValue(Name.SPECIFICATION_VERSION); 479 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); 480 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); 481 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); 482 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); 483 sealed = attr.getValue(Name.SEALED); 484 } 485 attr = man.getMainAttributes(); 486 if (attr != null) { 487 if (specTitle == null) { 488 specTitle = attr.getValue(Name.SPECIFICATION_TITLE); 489 } 490 if (specVersion == null) { 491 specVersion = attr.getValue(Name.SPECIFICATION_VERSION); 492 } 493 if (specVendor == null) { 494 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); 495 } 496 if (implTitle == null) { 497 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); 498 } 499 if (implVersion == null) { 500 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); 501 } 502 if (implVendor == null) { 503 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); 504 } 505 if (sealed == null) { 506 sealed = attr.getValue(Name.SEALED); 507 } 508 } 509 if ("true".equalsIgnoreCase(sealed)) { 510 sealBase = url; 511 } 512 return definePackage(name, specTitle, specVersion, specVendor, 513 implTitle, implVersion, implVendor, sealBase); 514 } 515 516 /* 517 * Returns true if the specified package name is sealed according to the 518 * given manifest. 519 */ 520 private boolean isSealed(String name, Manifest man) { 521 String path = name.replace('.', '/').concat("/"); 522 Attributes attr = man.getAttributes(path); 523 String sealed = null; 524 if (attr != null) { 525 sealed = attr.getValue(Name.SEALED); 526 } 527 if (sealed == null) { 528 if ((attr = man.getMainAttributes()) != null) { 529 sealed = attr.getValue(Name.SEALED); 530 } 531 } 532 return "true".equalsIgnoreCase(sealed); 533 } 534 535 /** 536 * Finds the resource with the specified name on the URL search path. 537 * 538 * @param name the name of the resource 539 * @return a <code>URL</code> for the resource, or <code>null</code> 540 * if the resource could not be found, or if the loader is closed. 541 */ 542 public URL findResource(final String name) { 543 /* 544 * The same restriction to finding classes applies to resources 545 */ 546 URL url = AccessController.doPrivileged( 547 new PrivilegedAction<URL>() { 548 public URL run() { 549 return ucp.findResource(name, true); 550 } 551 }, acc); 552 553 return url != null ? ucp.checkURL(url) : null; 554 } 555 556 /** 557 * Returns an Enumeration of URLs representing all of the resources 558 * on the URL search path having the specified name. 559 * 560 * @param name the resource name 561 * @exception IOException if an I/O exception occurs 562 * @return an <code>Enumeration</code> of <code>URL</code>s 563 * If the loader is closed, the Enumeration will be empty. 564 */ 565 public Enumeration<URL> findResources(final String name) 566 throws IOException 567 { 568 final Enumeration<URL> e = ucp.findResources(name, true); 569 570 return new Enumeration<URL>() { 571 private URL url = null; 572 573 private boolean next() { 574 if (url != null) { 575 return true; 576 } 577 do { 578 URL u = AccessController.doPrivileged( 579 new PrivilegedAction<URL>() { 580 public URL run() { 581 if (!e.hasMoreElements()) 582 return null; 583 return e.nextElement(); 584 } 585 }, acc); 586 if (u == null) 587 break; 588 url = ucp.checkURL(u); 589 } while (url == null); 590 return url != null; 591 } 592 593 public URL nextElement() { 594 if (!next()) { 595 throw new NoSuchElementException(); 596 } 597 URL u = url; 598 url = null; 599 return u; 600 } 601 602 public boolean hasMoreElements() { 603 return next(); 604 } 605 }; 606 } 607 608 /** 609 * Returns the permissions for the given codesource object. 610 * The implementation of this method first calls super.getPermissions 611 * and then adds permissions based on the URL of the codesource. 612 * <p> 613 * If the protocol of this URL is "jar", then the permission granted 614 * is based on the permission that is required by the URL of the Jar 615 * file. 616 * <p> 617 * If the protocol is "file" and there is an authority component, then 618 * permission to connect to and accept connections from that authority 619 * may be granted. If the protocol is "file" 620 * and the path specifies a file, then permission to read that 621 * file is granted. If protocol is "file" and the path is 622 * a directory, permission is granted to read all files 623 * and (recursively) all files and subdirectories contained in 624 * that directory. 625 * <p> 626 * If the protocol is not "file", then permission 627 * to connect to and accept connections from the URL's host is granted. 628 * @param codesource the codesource 629 * @return the permissions granted to the codesource 630 */ 631 protected PermissionCollection getPermissions(CodeSource codesource) 632 { 633 PermissionCollection perms = super.getPermissions(codesource); 634 635 URL url = codesource.getLocation(); 636 637 Permission p; 638 URLConnection urlConnection; 639 640 try { 641 urlConnection = url.openConnection(); 642 p = urlConnection.getPermission(); 643 } catch (java.io.IOException ioe) { 644 p = null; 645 urlConnection = null; 646 } 647 648 if (p instanceof FilePermission) { 649 // if the permission has a separator char on the end, 650 // it means the codebase is a directory, and we need 651 // to add an additional permission to read recursively 652 String path = p.getName(); 653 if (path.endsWith(File.separator)) { 654 path += "-"; 655 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION); 656 } 657 } else if ((p == null) && (url.getProtocol().equals("file"))) { 658 String path = url.getFile().replace('/', File.separatorChar); 659 path = ParseUtil.decode(path); 660 if (path.endsWith(File.separator)) 661 path += "-"; 662 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION); 663 } else { 664 /** 665 * Not loading from a 'file:' URL so we want to give the class 666 * permission to connect to and accept from the remote host 667 * after we've made sure the host is the correct one and is valid. 668 */ 669 URL locUrl = url; 670 if (urlConnection instanceof JarURLConnection) { 671 locUrl = ((JarURLConnection)urlConnection).getJarFileURL(); 672 } 673 String host = locUrl.getHost(); 674 if (host != null && (host.length() > 0)) 675 p = new SocketPermission(host, 676 SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION); 677 } 678 679 // make sure the person that created this class loader 680 // would have this permission 681 682 if (p != null) { 683 final SecurityManager sm = System.getSecurityManager(); 684 if (sm != null) { 685 final Permission fp = p; 686 AccessController.doPrivileged(new PrivilegedAction<Void>() { 687 public Void run() throws SecurityException { 688 sm.checkPermission(fp); 689 return null; 690 } 691 }, acc); 692 } 693 perms.add(p); 694 } 695 return perms; 696 } 697 698 /** 699 * Creates a new instance of URLClassLoader for the specified 700 * URLs and parent class loader. If a security manager is 701 * installed, the <code>loadClass</code> method of the URLClassLoader 702 * returned by this method will invoke the 703 * <code>SecurityManager.checkPackageAccess</code> method before 704 * loading the class. 705 * 706 * @param urls the URLs to search for classes and resources 707 * @param parent the parent class loader for delegation 708 * @return the resulting class loader 709 */ 710 public static URLClassLoader newInstance(final URL[] urls, 711 final ClassLoader parent) { 712 // Save the caller's context 713 final AccessControlContext acc = AccessController.getContext(); 714 // Need a privileged block to create the class loader 715 URLClassLoader ucl = AccessController.doPrivileged( 716 new PrivilegedAction<URLClassLoader>() { 717 public URLClassLoader run() { 718 return new FactoryURLClassLoader(urls, parent, acc); 719 } 720 }); 721 return ucl; 722 } 723 724 /** 725 * Creates a new instance of URLClassLoader for the specified 726 * URLs and default parent class loader. If a security manager is 727 * installed, the <code>loadClass</code> method of the URLClassLoader 728 * returned by this method will invoke the 729 * <code>SecurityManager.checkPackageAccess</code> before 730 * loading the class. 731 * 732 * @param urls the URLs to search for classes and resources 733 * @return the resulting class loader 734 */ 735 public static URLClassLoader newInstance(final URL[] urls) { 736 // Save the caller's context 737 final AccessControlContext acc = AccessController.getContext(); 738 // Need a privileged block to create the class loader 739 URLClassLoader ucl = AccessController.doPrivileged( 740 new PrivilegedAction<URLClassLoader>() { 741 public URLClassLoader run() { 742 return new FactoryURLClassLoader(urls, acc); 743 } 744 }); 745 return ucl; 746 } 747 748 static { 749 /*sun.misc.SharedSecrets.setJavaNetAccess ( 750 new sun.misc.JavaNetAccess() { 751 public URLClassPath getURLClassPath (URLClassLoader u) { 752 return u.ucp; 753 } 754 } 755 );*/ 756 ClassLoader.registerAsParallelCapable(); 757 } 758 } 759 760 final class FactoryURLClassLoader extends URLClassLoader { 761 762 static { 763 ClassLoader.registerAsParallelCapable(); 764 } 765 766 FactoryURLClassLoader(URL[] urls, ClassLoader parent, 767 AccessControlContext acc) { 768 super(urls, parent, acc); 769 } 770 771 FactoryURLClassLoader(URL[] urls, AccessControlContext acc) { 772 super(urls, acc); 773 } 774 775 public final Class loadClass(String name, boolean resolve) 776 throws ClassNotFoundException 777 { 778 // First check if we have permission to access the package. This 779 // should go away once we've added support for exported packages. 780 SecurityManager sm = System.getSecurityManager(); 781 if (sm != null) { 782 int i = name.lastIndexOf('.'); 783 if (i != -1) { 784 sm.checkPackageAccess(name.substring(0, i)); 785 } 786 } 787 return super.loadClass(name, resolve); 788 } 789 } 790