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