J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 1994-2005 Sun Microsystems, Inc. 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. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any questions. |
| 24 | */ |
| 25 | package java.lang; |
| 26 | |
| 27 | import java.io.InputStream; |
| 28 | import java.io.IOException; |
| 29 | import java.io.File; |
| 30 | import java.lang.reflect.Constructor; |
| 31 | import java.lang.reflect.InvocationTargetException; |
| 32 | import java.net.MalformedURLException; |
| 33 | import java.net.URL; |
| 34 | import java.security.AccessController; |
| 35 | import java.security.AccessControlContext; |
| 36 | import java.security.CodeSource; |
| 37 | import java.security.Policy; |
| 38 | import java.security.PrivilegedAction; |
| 39 | import java.security.PrivilegedActionException; |
| 40 | import java.security.PrivilegedExceptionAction; |
| 41 | import java.security.ProtectionDomain; |
| 42 | import java.util.Enumeration; |
| 43 | import java.util.Hashtable; |
| 44 | import java.util.HashMap; |
| 45 | import java.util.HashSet; |
| 46 | import java.util.Set; |
| 47 | import java.util.Stack; |
| 48 | import java.util.Map; |
| 49 | import java.util.Vector; |
| 50 | import sun.misc.ClassFileTransformer; |
| 51 | import sun.misc.CompoundEnumeration; |
| 52 | import sun.misc.Resource; |
| 53 | import sun.misc.URLClassPath; |
| 54 | import sun.misc.VM; |
| 55 | import sun.reflect.Reflection; |
| 56 | import sun.security.util.SecurityConstants; |
| 57 | |
| 58 | /** |
| 59 | * A class loader is an object that is responsible for loading classes. The |
| 60 | * class <tt>ClassLoader</tt> is an abstract class. Given the <a |
| 61 | * href="#name">binary name</a> of a class, a class loader should attempt to |
| 62 | * locate or generate data that constitutes a definition for the class. A |
| 63 | * typical strategy is to transform the name into a file name and then read a |
| 64 | * "class file" of that name from a file system. |
| 65 | * |
| 66 | * <p> Every {@link Class <tt>Class</tt>} object contains a {@link |
| 67 | * Class#getClassLoader() reference} to the <tt>ClassLoader</tt> that defined |
| 68 | * it. |
| 69 | * |
| 70 | * <p> <tt>Class</tt> objects for array classes are not created by class |
| 71 | * loaders, but are created automatically as required by the Java runtime. |
| 72 | * The class loader for an array class, as returned by {@link |
| 73 | * Class#getClassLoader()} is the same as the class loader for its element |
| 74 | * type; if the element type is a primitive type, then the array class has no |
| 75 | * class loader. |
| 76 | * |
| 77 | * <p> Applications implement subclasses of <tt>ClassLoader</tt> in order to |
| 78 | * extend the manner in which the Java virtual machine dynamically loads |
| 79 | * classes. |
| 80 | * |
| 81 | * <p> Class loaders may typically be used by security managers to indicate |
| 82 | * security domains. |
| 83 | * |
| 84 | * <p> The <tt>ClassLoader</tt> class uses a delegation model to search for |
| 85 | * classes and resources. Each instance of <tt>ClassLoader</tt> has an |
| 86 | * associated parent class loader. When requested to find a class or |
| 87 | * resource, a <tt>ClassLoader</tt> instance will delegate the search for the |
| 88 | * class or resource to its parent class loader before attempting to find the |
| 89 | * class or resource itself. The virtual machine's built-in class loader, |
| 90 | * called the "bootstrap class loader", does not itself have a parent but may |
| 91 | * serve as the parent of a <tt>ClassLoader</tt> instance. |
| 92 | * |
| 93 | * <p> Normally, the Java virtual machine loads classes from the local file |
| 94 | * system in a platform-dependent manner. For example, on UNIX systems, the |
| 95 | * virtual machine loads classes from the directory defined by the |
| 96 | * <tt>CLASSPATH</tt> environment variable. |
| 97 | * |
| 98 | * <p> However, some classes may not originate from a file; they may originate |
| 99 | * from other sources, such as the network, or they could be constructed by an |
| 100 | * application. The method {@link #defineClass(String, byte[], int, int) |
| 101 | * <tt>defineClass</tt>} converts an array of bytes into an instance of class |
| 102 | * <tt>Class</tt>. Instances of this newly defined class can be created using |
| 103 | * {@link Class#newInstance <tt>Class.newInstance</tt>}. |
| 104 | * |
| 105 | * <p> The methods and constructors of objects created by a class loader may |
| 106 | * reference other classes. To determine the class(es) referred to, the Java |
| 107 | * virtual machine invokes the {@link #loadClass <tt>loadClass</tt>} method of |
| 108 | * the class loader that originally created the class. |
| 109 | * |
| 110 | * <p> For example, an application could create a network class loader to |
| 111 | * download class files from a server. Sample code might look like: |
| 112 | * |
| 113 | * <blockquote><pre> |
| 114 | * ClassLoader loader = new NetworkClassLoader(host, port); |
| 115 | * Object main = loader.loadClass("Main", true).newInstance(); |
| 116 | * . . . |
| 117 | * </pre></blockquote> |
| 118 | * |
| 119 | * <p> The network class loader subclass must define the methods {@link |
| 120 | * #findClass <tt>findClass</tt>} and <tt>loadClassData</tt> to load a class |
| 121 | * from the network. Once it has downloaded the bytes that make up the class, |
| 122 | * it should use the method {@link #defineClass <tt>defineClass</tt>} to |
| 123 | * create a class instance. A sample implementation is: |
| 124 | * |
| 125 | * <blockquote><pre> |
| 126 | * class NetworkClassLoader extends ClassLoader { |
| 127 | * String host; |
| 128 | * int port; |
| 129 | * |
| 130 | * public Class findClass(String name) { |
| 131 | * byte[] b = loadClassData(name); |
| 132 | * return defineClass(name, b, 0, b.length); |
| 133 | * } |
| 134 | * |
| 135 | * private byte[] loadClassData(String name) { |
| 136 | * // load the class data from the connection |
| 137 | * . . . |
| 138 | * } |
| 139 | * } |
| 140 | * </pre></blockquote> |
| 141 | * |
| 142 | * <h4> <a name="name">Binary names</a> </h4> |
| 143 | * |
| 144 | * <p> Any class name provided as a {@link String} parameter to methods in |
| 145 | * <tt>ClassLoader</tt> must be a binary name as defined by the <a |
| 146 | * href="http://java.sun.com/docs/books/jls/">Java Language Specification</a>. |
| 147 | * |
| 148 | * <p> Examples of valid class names include: |
| 149 | * <blockquote><pre> |
| 150 | * "java.lang.String" |
| 151 | * "javax.swing.JSpinner$DefaultEditor" |
| 152 | * "java.security.KeyStore$Builder$FileBuilder$1" |
| 153 | * "java.net.URLClassLoader$3$1" |
| 154 | * </pre></blockquote> |
| 155 | * |
| 156 | * @see #resolveClass(Class) |
| 157 | * @since 1.0 |
| 158 | */ |
| 159 | public abstract class ClassLoader { |
| 160 | |
| 161 | private static native void registerNatives(); |
| 162 | static { |
| 163 | registerNatives(); |
| 164 | } |
| 165 | |
| 166 | // If initialization succeed this is set to true and security checks will |
| 167 | // succeed. Otherwise the object is not initialized and the object is |
| 168 | // useless. |
| 169 | private boolean initialized = false; |
| 170 | |
| 171 | // The parent class loader for delegation |
| 172 | private ClassLoader parent; |
| 173 | |
| 174 | // Hashtable that maps packages to certs |
| 175 | private Hashtable package2certs = new Hashtable(11); |
| 176 | |
| 177 | // Shared among all packages with unsigned classes |
| 178 | java.security.cert.Certificate[] nocerts; |
| 179 | |
| 180 | // The classes loaded by this class loader. The only purpose of this table |
| 181 | // is to keep the classes from being GC'ed until the loader is GC'ed. |
| 182 | private Vector classes = new Vector(); |
| 183 | |
| 184 | // The initiating protection domains for all classes loaded by this loader |
| 185 | private Set domains = new HashSet(); |
| 186 | |
| 187 | // Invoked by the VM to record every loaded class with this loader. |
| 188 | void addClass(Class c) { |
| 189 | classes.addElement(c); |
| 190 | } |
| 191 | |
| 192 | // The packages defined in this class loader. Each package name is mapped |
| 193 | // to its corresponding Package object. |
| 194 | private HashMap packages = new HashMap(); |
| 195 | |
| 196 | /** |
| 197 | * Creates a new class loader using the specified parent class loader for |
| 198 | * delegation. |
| 199 | * |
| 200 | * <p> If there is a security manager, its {@link |
| 201 | * SecurityManager#checkCreateClassLoader() |
| 202 | * <tt>checkCreateClassLoader</tt>} method is invoked. This may result in |
| 203 | * a security exception. </p> |
| 204 | * |
| 205 | * @param parent |
| 206 | * The parent class loader |
| 207 | * |
| 208 | * @throws SecurityException |
| 209 | * If a security manager exists and its |
| 210 | * <tt>checkCreateClassLoader</tt> method doesn't allow creation |
| 211 | * of a new class loader. |
| 212 | * |
| 213 | * @since 1.2 |
| 214 | */ |
| 215 | protected ClassLoader(ClassLoader parent) { |
| 216 | SecurityManager security = System.getSecurityManager(); |
| 217 | if (security != null) { |
| 218 | security.checkCreateClassLoader(); |
| 219 | } |
| 220 | this.parent = parent; |
| 221 | initialized = true; |
| 222 | } |
| 223 | |
| 224 | /** |
| 225 | * Creates a new class loader using the <tt>ClassLoader</tt> returned by |
| 226 | * the method {@link #getSystemClassLoader() |
| 227 | * <tt>getSystemClassLoader()</tt>} as the parent class loader. |
| 228 | * |
| 229 | * <p> If there is a security manager, its {@link |
| 230 | * SecurityManager#checkCreateClassLoader() |
| 231 | * <tt>checkCreateClassLoader</tt>} method is invoked. This may result in |
| 232 | * a security exception. </p> |
| 233 | * |
| 234 | * @throws SecurityException |
| 235 | * If a security manager exists and its |
| 236 | * <tt>checkCreateClassLoader</tt> method doesn't allow creation |
| 237 | * of a new class loader. |
| 238 | */ |
| 239 | protected ClassLoader() { |
| 240 | SecurityManager security = System.getSecurityManager(); |
| 241 | if (security != null) { |
| 242 | security.checkCreateClassLoader(); |
| 243 | } |
| 244 | this.parent = getSystemClassLoader(); |
| 245 | initialized = true; |
| 246 | } |
| 247 | |
| 248 | |
| 249 | // -- Class -- |
| 250 | |
| 251 | /** |
| 252 | * Loads the class with the specified <a href="#name">binary name</a>. |
| 253 | * This method searches for classes in the same manner as the {@link |
| 254 | * #loadClass(String, boolean)} method. It is invoked by the Java virtual |
| 255 | * machine to resolve class references. Invoking this method is equivalent |
| 256 | * to invoking {@link #loadClass(String, boolean) <tt>loadClass(name, |
| 257 | * false)</tt>}. </p> |
| 258 | * |
| 259 | * @param name |
| 260 | * The <a href="#name">binary name</a> of the class |
| 261 | * |
| 262 | * @return The resulting <tt>Class</tt> object |
| 263 | * |
| 264 | * @throws ClassNotFoundException |
| 265 | * If the class was not found |
| 266 | */ |
| 267 | public Class<?> loadClass(String name) throws ClassNotFoundException { |
| 268 | return loadClass(name, false); |
| 269 | } |
| 270 | |
| 271 | /** |
| 272 | * Loads the class with the specified <a href="#name">binary name</a>. The |
| 273 | * default implementation of this method searches for classes in the |
| 274 | * following order: |
| 275 | * |
| 276 | * <p><ol> |
| 277 | * |
| 278 | * <li><p> Invoke {@link #findLoadedClass(String)} to check if the class |
| 279 | * has already been loaded. </p></li> |
| 280 | * |
| 281 | * <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method |
| 282 | * on the parent class loader. If the parent is <tt>null</tt> the class |
| 283 | * loader built-in to the virtual machine is used, instead. </p></li> |
| 284 | * |
| 285 | * <li><p> Invoke the {@link #findClass(String)} method to find the |
| 286 | * class. </p></li> |
| 287 | * |
| 288 | * </ol> |
| 289 | * |
| 290 | * <p> If the class was found using the above steps, and the |
| 291 | * <tt>resolve</tt> flag is true, this method will then invoke the {@link |
| 292 | * #resolveClass(Class)} method on the resulting <tt>Class</tt> object. |
| 293 | * |
| 294 | * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link |
| 295 | * #findClass(String)}, rather than this method. </p> |
| 296 | * |
| 297 | * @param name |
| 298 | * The <a href="#name">binary name</a> of the class |
| 299 | * |
| 300 | * @param resolve |
| 301 | * If <tt>true</tt> then resolve the class |
| 302 | * |
| 303 | * @return The resulting <tt>Class</tt> object |
| 304 | * |
| 305 | * @throws ClassNotFoundException |
| 306 | * If the class could not be found |
| 307 | */ |
| 308 | protected synchronized Class<?> loadClass(String name, boolean resolve) |
| 309 | throws ClassNotFoundException |
| 310 | { |
| 311 | // First, check if the class has already been loaded |
| 312 | Class c = findLoadedClass(name); |
| 313 | if (c == null) { |
| 314 | try { |
| 315 | if (parent != null) { |
| 316 | c = parent.loadClass(name, false); |
| 317 | } else { |
| 318 | c = findBootstrapClass0(name); |
| 319 | } |
| 320 | } catch (ClassNotFoundException e) { |
| 321 | // If still not found, then invoke findClass in order |
| 322 | // to find the class. |
| 323 | c = findClass(name); |
| 324 | } |
| 325 | } |
| 326 | if (resolve) { |
| 327 | resolveClass(c); |
| 328 | } |
| 329 | return c; |
| 330 | } |
| 331 | |
| 332 | // This method is invoked by the virtual machine to load a class. |
| 333 | private synchronized Class loadClassInternal(String name) |
| 334 | throws ClassNotFoundException |
| 335 | { |
| 336 | return loadClass(name); |
| 337 | } |
| 338 | |
| 339 | private void checkPackageAccess(Class cls, ProtectionDomain pd) { |
| 340 | final SecurityManager sm = System.getSecurityManager(); |
| 341 | if (sm != null) { |
| 342 | final String name = cls.getName(); |
| 343 | final int i = name.lastIndexOf('.'); |
| 344 | if (i != -1) { |
| 345 | AccessController.doPrivileged(new PrivilegedAction() { |
| 346 | public Object run() { |
| 347 | sm.checkPackageAccess(name.substring(0, i)); |
| 348 | return null; |
| 349 | } |
| 350 | }, new AccessControlContext(new ProtectionDomain[] {pd})); |
| 351 | } |
| 352 | } |
| 353 | domains.add(pd); |
| 354 | } |
| 355 | |
| 356 | /** |
| 357 | * Finds the class with the specified <a href="#name">binary name</a>. |
| 358 | * This method should be overridden by class loader implementations that |
| 359 | * follow the delegation model for loading classes, and will be invoked by |
| 360 | * the {@link #loadClass <tt>loadClass</tt>} method after checking the |
| 361 | * parent class loader for the requested class. The default implementation |
| 362 | * throws a <tt>ClassNotFoundException</tt>. </p> |
| 363 | * |
| 364 | * @param name |
| 365 | * The <a href="#name">binary name</a> of the class |
| 366 | * |
| 367 | * @return The resulting <tt>Class</tt> object |
| 368 | * |
| 369 | * @throws ClassNotFoundException |
| 370 | * If the class could not be found |
| 371 | * |
| 372 | * @since 1.2 |
| 373 | */ |
| 374 | protected Class<?> findClass(String name) throws ClassNotFoundException { |
| 375 | throw new ClassNotFoundException(name); |
| 376 | } |
| 377 | |
| 378 | /** |
| 379 | * Converts an array of bytes into an instance of class <tt>Class</tt>. |
| 380 | * Before the <tt>Class</tt> can be used it must be resolved. This method |
| 381 | * is deprecated in favor of the version that takes a <a |
| 382 | * href="#name">binary name</a> as its first argument, and is more secure. |
| 383 | * |
| 384 | * @param b |
| 385 | * The bytes that make up the class data. The bytes in positions |
| 386 | * <tt>off</tt> through <tt>off+len-1</tt> should have the format |
| 387 | * of a valid class file as defined by the <a |
| 388 | * href="http://java.sun.com/docs/books/vmspec/">Java Virtual |
| 389 | * Machine Specification</a>. |
| 390 | * |
| 391 | * @param off |
| 392 | * The start offset in <tt>b</tt> of the class data |
| 393 | * |
| 394 | * @param len |
| 395 | * The length of the class data |
| 396 | * |
| 397 | * @return The <tt>Class</tt> object that was created from the specified |
| 398 | * class data |
| 399 | * |
| 400 | * @throws ClassFormatError |
| 401 | * If the data did not contain a valid class |
| 402 | * |
| 403 | * @throws IndexOutOfBoundsException |
| 404 | * If either <tt>off</tt> or <tt>len</tt> is negative, or if |
| 405 | * <tt>off+len</tt> is greater than <tt>b.length</tt>. |
| 406 | * |
| 407 | * @see #loadClass(String, boolean) |
| 408 | * @see #resolveClass(Class) |
| 409 | * |
| 410 | * @deprecated Replaced by {@link #defineClass(String, byte[], int, int) |
| 411 | * defineClass(String, byte[], int, int)} |
| 412 | */ |
| 413 | @Deprecated |
| 414 | protected final Class<?> defineClass(byte[] b, int off, int len) |
| 415 | throws ClassFormatError |
| 416 | { |
| 417 | return defineClass(null, b, off, len, null); |
| 418 | } |
| 419 | |
| 420 | /** |
| 421 | * Converts an array of bytes into an instance of class <tt>Class</tt>. |
| 422 | * Before the <tt>Class</tt> can be used it must be resolved. |
| 423 | * |
| 424 | * <p> This method assigns a default {@link java.security.ProtectionDomain |
| 425 | * <tt>ProtectionDomain</tt>} to the newly defined class. The |
| 426 | * <tt>ProtectionDomain</tt> is effectively granted the same set of |
| 427 | * permissions returned when {@link |
| 428 | * java.security.Policy#getPermissions(java.security.CodeSource) |
| 429 | * <tt>Policy.getPolicy().getPermissions(new CodeSource(null, null))</tt>} |
| 430 | * is invoked. The default domain is created on the first invocation of |
| 431 | * {@link #defineClass(String, byte[], int, int) <tt>defineClass</tt>}, |
| 432 | * and re-used on subsequent invocations. |
| 433 | * |
| 434 | * <p> To assign a specific <tt>ProtectionDomain</tt> to the class, use |
| 435 | * the {@link #defineClass(String, byte[], int, int, |
| 436 | * java.security.ProtectionDomain) <tt>defineClass</tt>} method that takes a |
| 437 | * <tt>ProtectionDomain</tt> as one of its arguments. </p> |
| 438 | * |
| 439 | * @param name |
| 440 | * The expected <a href="#name">binary name</a> of the class, or |
| 441 | * <tt>null</tt> if not known |
| 442 | * |
| 443 | * @param b |
| 444 | * The bytes that make up the class data. The bytes in positions |
| 445 | * <tt>off</tt> through <tt>off+len-1</tt> should have the format |
| 446 | * of a valid class file as defined by the <a |
| 447 | * href="http://java.sun.com/docs/books/vmspec/">Java Virtual |
| 448 | * Machine Specification</a>. |
| 449 | * |
| 450 | * @param off |
| 451 | * The start offset in <tt>b</tt> of the class data |
| 452 | * |
| 453 | * @param len |
| 454 | * The length of the class data |
| 455 | * |
| 456 | * @return The <tt>Class</tt> object that was created from the specified |
| 457 | * class data. |
| 458 | * |
| 459 | * @throws ClassFormatError |
| 460 | * If the data did not contain a valid class |
| 461 | * |
| 462 | * @throws IndexOutOfBoundsException |
| 463 | * If either <tt>off</tt> or <tt>len</tt> is negative, or if |
| 464 | * <tt>off+len</tt> is greater than <tt>b.length</tt>. |
| 465 | * |
| 466 | * @throws SecurityException |
| 467 | * If an attempt is made to add this class to a package that |
| 468 | * contains classes that were signed by a different set of |
| 469 | * certificates than this class (which is unsigned), or if |
| 470 | * <tt>name</tt> begins with "<tt>java.</tt>". |
| 471 | * |
| 472 | * @see #loadClass(String, boolean) |
| 473 | * @see #resolveClass(Class) |
| 474 | * @see java.security.CodeSource |
| 475 | * @see java.security.SecureClassLoader |
| 476 | * |
| 477 | * @since 1.1 |
| 478 | */ |
| 479 | protected final Class<?> defineClass(String name, byte[] b, int off, int len) |
| 480 | throws ClassFormatError |
| 481 | { |
| 482 | return defineClass(name, b, off, len, null); |
| 483 | } |
| 484 | |
| 485 | /* Determine protection domain, and check that: |
| 486 | - not define java.* class, |
| 487 | - signer of this class matches signers for the rest of the classes in package. |
| 488 | */ |
| 489 | private ProtectionDomain preDefineClass(String name, |
| 490 | ProtectionDomain protectionDomain) |
| 491 | { |
| 492 | if (!checkName(name)) |
| 493 | throw new NoClassDefFoundError("IllegalName: " + name); |
| 494 | |
| 495 | if ((name != null) && name.startsWith("java.")) { |
| 496 | throw new SecurityException("Prohibited package name: " + |
| 497 | name.substring(0, name.lastIndexOf('.'))); |
| 498 | } |
| 499 | if (protectionDomain == null) { |
| 500 | protectionDomain = getDefaultDomain(); |
| 501 | } |
| 502 | |
| 503 | if (name != null) |
| 504 | checkCerts(name, protectionDomain.getCodeSource()); |
| 505 | |
| 506 | return protectionDomain; |
| 507 | } |
| 508 | |
| 509 | private String defineClassSourceLocation(ProtectionDomain protectionDomain) |
| 510 | { |
| 511 | CodeSource cs = protectionDomain.getCodeSource(); |
| 512 | String source = null; |
| 513 | if (cs != null && cs.getLocation() != null) { |
| 514 | source = cs.getLocation().toString(); |
| 515 | } |
| 516 | return source; |
| 517 | } |
| 518 | |
| 519 | private Class defineTransformedClass(String name, byte[] b, int off, int len, |
| 520 | ProtectionDomain protectionDomain, |
| 521 | ClassFormatError cfe, String source) |
| 522 | throws ClassFormatError |
| 523 | { |
| 524 | // Class format error - try to transform the bytecode and |
| 525 | // define the class again |
| 526 | // |
| 527 | Object[] transformers = ClassFileTransformer.getTransformers(); |
| 528 | Class c = null; |
| 529 | |
| 530 | for (int i = 0; transformers != null && i < transformers.length; i++) { |
| 531 | try { |
| 532 | // Transform byte code using transformer |
| 533 | byte[] tb = ((ClassFileTransformer) transformers[i]).transform(b, off, len); |
| 534 | c = defineClass1(name, tb, 0, tb.length, protectionDomain, source); |
| 535 | break; |
| 536 | } catch (ClassFormatError cfe2) { |
| 537 | // If ClassFormatError occurs, try next transformer |
| 538 | } |
| 539 | } |
| 540 | |
| 541 | // Rethrow original ClassFormatError if unable to transform |
| 542 | // bytecode to well-formed |
| 543 | // |
| 544 | if (c == null) |
| 545 | throw cfe; |
| 546 | |
| 547 | return c; |
| 548 | } |
| 549 | |
| 550 | private void postDefineClass(Class c, ProtectionDomain protectionDomain) |
| 551 | { |
| 552 | if (protectionDomain.getCodeSource() != null) { |
| 553 | java.security.cert.Certificate certs[] = |
| 554 | protectionDomain.getCodeSource().getCertificates(); |
| 555 | if (certs != null) |
| 556 | setSigners(c, certs); |
| 557 | } |
| 558 | } |
| 559 | |
| 560 | /** |
| 561 | * Converts an array of bytes into an instance of class <tt>Class</tt>, |
| 562 | * with an optional <tt>ProtectionDomain</tt>. If the domain is |
| 563 | * <tt>null</tt>, then a default domain will be assigned to the class as |
| 564 | * specified in the documentation for {@link #defineClass(String, byte[], |
| 565 | * int, int)}. Before the class can be used it must be resolved. |
| 566 | * |
| 567 | * <p> The first class defined in a package determines the exact set of |
| 568 | * certificates that all subsequent classes defined in that package must |
| 569 | * contain. The set of certificates for a class is obtained from the |
| 570 | * {@link java.security.CodeSource <tt>CodeSource</tt>} within the |
| 571 | * <tt>ProtectionDomain</tt> of the class. Any classes added to that |
| 572 | * package must contain the same set of certificates or a |
| 573 | * <tt>SecurityException</tt> will be thrown. Note that if |
| 574 | * <tt>name</tt> is <tt>null</tt>, this check is not performed. |
| 575 | * You should always pass in the <a href="#name">binary name</a> of the |
| 576 | * class you are defining as well as the bytes. This ensures that the |
| 577 | * class you are defining is indeed the class you think it is. |
| 578 | * |
| 579 | * <p> The specified <tt>name</tt> cannot begin with "<tt>java.</tt>", since |
| 580 | * all classes in the "<tt>java.*</tt> packages can only be defined by the |
| 581 | * bootstrap class loader. If <tt>name</tt> is not <tt>null</tt>, it |
| 582 | * must be equal to the <a href="#name">binary name</a> of the class |
| 583 | * specified by the byte array "<tt>b</tt>", otherwise a {@link |
| 584 | * <tt>NoClassDefFoundError</tt>} will be thrown. </p> |
| 585 | * |
| 586 | * @param name |
| 587 | * The expected <a href="#name">binary name</a> of the class, or |
| 588 | * <tt>null</tt> if not known |
| 589 | * |
| 590 | * @param b |
| 591 | * The bytes that make up the class data. The bytes in positions |
| 592 | * <tt>off</tt> through <tt>off+len-1</tt> should have the format |
| 593 | * of a valid class file as defined by the <a |
| 594 | * href="http://java.sun.com/docs/books/vmspec/">Java Virtual |
| 595 | * Machine Specification</a>. |
| 596 | * |
| 597 | * @param off |
| 598 | * The start offset in <tt>b</tt> of the class data |
| 599 | * |
| 600 | * @param len |
| 601 | * The length of the class data |
| 602 | * |
| 603 | * @param protectionDomain |
| 604 | * The ProtectionDomain of the class |
| 605 | * |
| 606 | * @return The <tt>Class</tt> object created from the data, |
| 607 | * and optional <tt>ProtectionDomain</tt>. |
| 608 | * |
| 609 | * @throws ClassFormatError |
| 610 | * If the data did not contain a valid class |
| 611 | * |
| 612 | * @throws NoClassDefFoundError |
| 613 | * If <tt>name</tt> is not equal to the <a href="#name">binary |
| 614 | * name</a> of the class specified by <tt>b</tt> |
| 615 | * |
| 616 | * @throws IndexOutOfBoundsException |
| 617 | * If either <tt>off</tt> or <tt>len</tt> is negative, or if |
| 618 | * <tt>off+len</tt> is greater than <tt>b.length</tt>. |
| 619 | * |
| 620 | * @throws SecurityException |
| 621 | * If an attempt is made to add this class to a package that |
| 622 | * contains classes that were signed by a different set of |
| 623 | * certificates than this class, or if <tt>name</tt> begins with |
| 624 | * "<tt>java.</tt>". |
| 625 | */ |
| 626 | protected final Class<?> defineClass(String name, byte[] b, int off, int len, |
| 627 | ProtectionDomain protectionDomain) |
| 628 | throws ClassFormatError |
| 629 | { |
| 630 | check(); |
| 631 | protectionDomain = preDefineClass(name, protectionDomain); |
| 632 | |
| 633 | Class c = null; |
| 634 | String source = defineClassSourceLocation(protectionDomain); |
| 635 | |
| 636 | try { |
| 637 | c = defineClass1(name, b, off, len, protectionDomain, source); |
| 638 | } catch (ClassFormatError cfe) { |
| 639 | c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source); |
| 640 | } |
| 641 | |
| 642 | postDefineClass(c, protectionDomain); |
| 643 | return c; |
| 644 | } |
| 645 | |
| 646 | /** |
| 647 | * Converts a {@link java.nio.ByteBuffer <tt>ByteBuffer</tt>} |
| 648 | * into an instance of class <tt>Class</tt>, |
| 649 | * with an optional <tt>ProtectionDomain</tt>. If the domain is |
| 650 | * <tt>null</tt>, then a default domain will be assigned to the class as |
| 651 | * specified in the documentation for {@link #defineClass(String, byte[], |
| 652 | * int, int)}. Before the class can be used it must be resolved. |
| 653 | * |
| 654 | * <p>The rules about the first class defined in a package determining the set of |
| 655 | * certificates for the package, and the restrictions on class names are identical |
| 656 | * to those specified in the documentation for {@link #defineClass(String, byte[], |
| 657 | * int, int, ProtectionDomain)}. |
| 658 | * |
| 659 | * <p> An invocation of this method of the form |
| 660 | * <i>cl</i><tt>.defineClass(</tt><i>name</i><tt>,</tt> |
| 661 | * <i>bBuffer</i><tt>,</tt> <i>pd</i><tt>)</tt> yields exactly the same |
| 662 | * result as the statements |
| 663 | * |
| 664 | * <blockquote><tt> |
| 665 | * ...<br> |
| 666 | * byte[] temp = new byte[</tt><i>bBuffer</i><tt>.{@link java.nio.ByteBuffer#remaining |
| 667 | * remaining}()];<br> |
| 668 | * </tt><i>bBuffer</i><tt>.{@link java.nio.ByteBuffer#get(byte[]) |
| 669 | * get}(temp);<br> |
| 670 | * return {@link #defineClass(String, byte[], int, int, ProtectionDomain) |
| 671 | * </tt><i>cl</i><tt>.defineClass}(</tt><i>name</i><tt>, temp, 0, temp.length, </tt><i>pd</i><tt>);<br> |
| 672 | * </tt></blockquote> |
| 673 | * |
| 674 | * @param name |
| 675 | * The expected <a href="#name">binary name</a. of the class, or |
| 676 | * <tt>null</tt> if not known |
| 677 | * |
| 678 | * @param b |
| 679 | * The bytes that make up the class data. The bytes from positions |
| 680 | * <tt>b.position()</tt> through <tt>b.position() + b.limit() -1 </tt> |
| 681 | * should have the format of a valid class file as defined by the <a |
| 682 | * href="http://java.sun.com/docs/books/vmspec/">Java Virtual |
| 683 | * Machine Specification</a>. |
| 684 | * |
| 685 | * @param protectionDomain |
| 686 | * The ProtectionDomain of the class, or <tt>null</tt>. |
| 687 | * |
| 688 | * @return The <tt>Class</tt> object created from the data, |
| 689 | * and optional <tt>ProtectionDomain</tt>. |
| 690 | * |
| 691 | * @throws ClassFormatError |
| 692 | * If the data did not contain a valid class. |
| 693 | * |
| 694 | * @throws NoClassDefFoundError |
| 695 | * If <tt>name</tt> is not equal to the <a href="#name">binary |
| 696 | * name</a> of the class specified by <tt>b</tt> |
| 697 | * |
| 698 | * @throws SecurityException |
| 699 | * If an attempt is made to add this class to a package that |
| 700 | * contains classes that were signed by a different set of |
| 701 | * certificates than this class, or if <tt>name</tt> begins with |
| 702 | * "<tt>java.</tt>". |
| 703 | * |
| 704 | * @see #defineClass(String, byte[], int, int, ProtectionDomain) |
| 705 | * |
| 706 | * @since 1.5 |
| 707 | */ |
| 708 | protected final Class<?> defineClass(String name, java.nio.ByteBuffer b, |
| 709 | ProtectionDomain protectionDomain) |
| 710 | throws ClassFormatError |
| 711 | { |
| 712 | check(); |
| 713 | |
| 714 | int len = b.remaining(); |
| 715 | |
| 716 | // Use byte[] if not a direct ByteBufer: |
| 717 | if (!b.isDirect()) { |
| 718 | if (b.hasArray()) { |
| 719 | return defineClass(name, b.array(), |
| 720 | b.position() + b.arrayOffset(), len, |
| 721 | protectionDomain); |
| 722 | } else { |
| 723 | // no array, or read-only array |
| 724 | byte[] tb = new byte[len]; |
| 725 | b.get(tb); // get bytes out of byte buffer. |
| 726 | return defineClass(name, tb, 0, len, protectionDomain); |
| 727 | } |
| 728 | } |
| 729 | |
| 730 | protectionDomain = preDefineClass(name, protectionDomain); |
| 731 | |
| 732 | Class c = null; |
| 733 | String source = defineClassSourceLocation(protectionDomain); |
| 734 | |
| 735 | try { |
| 736 | c = defineClass2(name, b, b.position(), len, protectionDomain, source); |
| 737 | } catch (ClassFormatError cfe) { |
| 738 | byte[] tb = new byte[len]; |
| 739 | b.get(tb); // get bytes out of byte buffer. |
| 740 | c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe, source); |
| 741 | } |
| 742 | |
| 743 | postDefineClass(c, protectionDomain); |
| 744 | return c; |
| 745 | } |
| 746 | |
| 747 | private native Class defineClass0(String name, byte[] b, int off, int len, |
| 748 | ProtectionDomain pd); |
| 749 | |
| 750 | private native Class defineClass1(String name, byte[] b, int off, int len, |
| 751 | ProtectionDomain pd, String source); |
| 752 | |
| 753 | private native Class defineClass2(String name, java.nio.ByteBuffer b, |
| 754 | int off, int len, ProtectionDomain pd, |
| 755 | String source); |
| 756 | |
| 757 | // true if the name is null or has the potential to be a valid binary name |
| 758 | private boolean checkName(String name) { |
| 759 | if ((name == null) || (name.length() == 0)) |
| 760 | return true; |
| 761 | if ((name.indexOf('/') != -1) |
| 762 | || (!VM.allowArraySyntax() && (name.charAt(0) == '['))) |
| 763 | return false; |
| 764 | return true; |
| 765 | } |
| 766 | |
| 767 | private synchronized void checkCerts(String name, CodeSource cs) { |
| 768 | int i = name.lastIndexOf('.'); |
| 769 | String pname = (i == -1) ? "" : name.substring(0, i); |
| 770 | java.security.cert.Certificate[] pcerts = |
| 771 | (java.security.cert.Certificate[]) package2certs.get(pname); |
| 772 | if (pcerts == null) { |
| 773 | // first class in this package gets to define which |
| 774 | // certificates must be the same for all other classes |
| 775 | // in this package |
| 776 | if (cs != null) { |
| 777 | pcerts = cs.getCertificates(); |
| 778 | } |
| 779 | if (pcerts == null) { |
| 780 | if (nocerts == null) |
| 781 | nocerts = new java.security.cert.Certificate[0]; |
| 782 | pcerts = nocerts; |
| 783 | } |
| 784 | package2certs.put(pname, pcerts); |
| 785 | } else { |
| 786 | java.security.cert.Certificate[] certs = null; |
| 787 | if (cs != null) { |
| 788 | certs = cs.getCertificates(); |
| 789 | } |
| 790 | |
| 791 | if (!compareCerts(pcerts, certs)) { |
| 792 | throw new SecurityException("class \""+ name + |
| 793 | "\"'s signer information does not match signer information of other classes in the same package"); |
| 794 | } |
| 795 | } |
| 796 | } |
| 797 | |
| 798 | /** |
| 799 | * check to make sure the certs for the new class (certs) are the same as |
| 800 | * the certs for the first class inserted in the package (pcerts) |
| 801 | */ |
| 802 | private boolean compareCerts(java.security.cert.Certificate[] pcerts, |
| 803 | java.security.cert.Certificate[] certs) |
| 804 | { |
| 805 | // certs can be null, indicating no certs. |
| 806 | if ((certs == null) || (certs.length == 0)) { |
| 807 | return pcerts.length == 0; |
| 808 | } |
| 809 | |
| 810 | // the length must be the same at this point |
| 811 | if (certs.length != pcerts.length) |
| 812 | return false; |
| 813 | |
| 814 | // go through and make sure all the certs in one array |
| 815 | // are in the other and vice-versa. |
| 816 | boolean match; |
| 817 | for (int i = 0; i < certs.length; i++) { |
| 818 | match = false; |
| 819 | for (int j = 0; j < pcerts.length; j++) { |
| 820 | if (certs[i].equals(pcerts[j])) { |
| 821 | match = true; |
| 822 | break; |
| 823 | } |
| 824 | } |
| 825 | if (!match) return false; |
| 826 | } |
| 827 | |
| 828 | // now do the same for pcerts |
| 829 | for (int i = 0; i < pcerts.length; i++) { |
| 830 | match = false; |
| 831 | for (int j = 0; j < certs.length; j++) { |
| 832 | if (pcerts[i].equals(certs[j])) { |
| 833 | match = true; |
| 834 | break; |
| 835 | } |
| 836 | } |
| 837 | if (!match) return false; |
| 838 | } |
| 839 | |
| 840 | return true; |
| 841 | } |
| 842 | |
| 843 | /** |
| 844 | * Links the specified class. This (misleadingly named) method may be |
| 845 | * used by a class loader to link a class. If the class <tt>c</tt> has |
| 846 | * already been linked, then this method simply returns. Otherwise, the |
| 847 | * class is linked as described in the "Execution" chapter of the <a |
| 848 | * href="http://java.sun.com/docs/books/jls/">Java Language |
| 849 | * Specification</a>. |
| 850 | * </p> |
| 851 | * |
| 852 | * @param c |
| 853 | * The class to link |
| 854 | * |
| 855 | * @throws NullPointerException |
| 856 | * If <tt>c</tt> is <tt>null</tt>. |
| 857 | * |
| 858 | * @see #defineClass(String, byte[], int, int) |
| 859 | */ |
| 860 | protected final void resolveClass(Class<?> c) { |
| 861 | check(); |
| 862 | resolveClass0(c); |
| 863 | } |
| 864 | |
| 865 | private native void resolveClass0(Class c); |
| 866 | |
| 867 | /** |
| 868 | * Finds a class with the specified <a href="#name">binary name</a>, |
| 869 | * loading it if necessary. |
| 870 | * |
| 871 | * <p> This method loads the class through the system class loader (see |
| 872 | * {@link #getSystemClassLoader()}). The <tt>Class</tt> object returned |
| 873 | * might have more than one <tt>ClassLoader</tt> associated with it. |
| 874 | * Subclasses of <tt>ClassLoader</tt> need not usually invoke this method, |
| 875 | * because most class loaders need to override just {@link |
| 876 | * #findClass(String)}. </p> |
| 877 | * |
| 878 | * @param name |
| 879 | * The <a href="#name">binary name</a> of the class |
| 880 | * |
| 881 | * @return The <tt>Class</tt> object for the specified <tt>name</tt> |
| 882 | * |
| 883 | * @throws ClassNotFoundException |
| 884 | * If the class could not be found |
| 885 | * |
| 886 | * @see #ClassLoader(ClassLoader) |
| 887 | * @see #getParent() |
| 888 | */ |
| 889 | protected final Class<?> findSystemClass(String name) |
| 890 | throws ClassNotFoundException |
| 891 | { |
| 892 | check(); |
| 893 | ClassLoader system = getSystemClassLoader(); |
| 894 | if (system == null) { |
| 895 | if (!checkName(name)) |
| 896 | throw new ClassNotFoundException(name); |
| 897 | return findBootstrapClass(name); |
| 898 | } |
| 899 | return system.loadClass(name); |
| 900 | } |
| 901 | |
| 902 | private Class findBootstrapClass0(String name) |
| 903 | throws ClassNotFoundException |
| 904 | { |
| 905 | check(); |
| 906 | if (!checkName(name)) |
| 907 | throw new ClassNotFoundException(name); |
| 908 | return findBootstrapClass(name); |
| 909 | } |
| 910 | |
| 911 | private native Class findBootstrapClass(String name) |
| 912 | throws ClassNotFoundException; |
| 913 | |
| 914 | // Check to make sure the class loader has been initialized. |
| 915 | private void check() { |
| 916 | if (!initialized) { |
| 917 | throw new SecurityException("ClassLoader object not initialized"); |
| 918 | } |
| 919 | } |
| 920 | |
| 921 | /** |
| 922 | * Returns the class with the given <a href="#name">binary name</a> if this |
| 923 | * loader has been recorded by the Java virtual machine as an initiating |
| 924 | * loader of a class with that <a href="#name">binary name</a>. Otherwise |
| 925 | * <tt>null</tt> is returned. </p> |
| 926 | * |
| 927 | * @param name |
| 928 | * The <a href="#name">binary name</a> of the class |
| 929 | * |
| 930 | * @return The <tt>Class</tt> object, or <tt>null</tt> if the class has |
| 931 | * not been loaded |
| 932 | * |
| 933 | * @since 1.1 |
| 934 | */ |
| 935 | protected final Class<?> findLoadedClass(String name) { |
| 936 | check(); |
| 937 | if (!checkName(name)) |
| 938 | return null; |
| 939 | return findLoadedClass0(name); |
| 940 | } |
| 941 | |
| 942 | private native final Class findLoadedClass0(String name); |
| 943 | |
| 944 | /** |
| 945 | * Sets the signers of a class. This should be invoked after defining a |
| 946 | * class. </p> |
| 947 | * |
| 948 | * @param c |
| 949 | * The <tt>Class</tt> object |
| 950 | * |
| 951 | * @param signers |
| 952 | * The signers for the class |
| 953 | * |
| 954 | * @since 1.1 |
| 955 | */ |
| 956 | protected final void setSigners(Class<?> c, Object[] signers) { |
| 957 | check(); |
| 958 | c.setSigners(signers); |
| 959 | } |
| 960 | |
| 961 | |
| 962 | // -- Resource -- |
| 963 | |
| 964 | /** |
| 965 | * Finds the resource with the given name. A resource is some data |
| 966 | * (images, audio, text, etc) that can be accessed by class code in a way |
| 967 | * that is independent of the location of the code. |
| 968 | * |
| 969 | * <p> The name of a resource is a '<tt>/</tt>'-separated path name that |
| 970 | * identifies the resource. |
| 971 | * |
| 972 | * <p> This method will first search the parent class loader for the |
| 973 | * resource; if the parent is <tt>null</tt> the path of the class loader |
| 974 | * built-in to the virtual machine is searched. That failing, this method |
| 975 | * will invoke {@link #findResource(String)} to find the resource. </p> |
| 976 | * |
| 977 | * @param name |
| 978 | * The resource name |
| 979 | * |
| 980 | * @return A <tt>URL</tt> object for reading the resource, or |
| 981 | * <tt>null</tt> if the resource could not be found or the invoker |
| 982 | * doesn't have adequate privileges to get the resource. |
| 983 | * |
| 984 | * @since 1.1 |
| 985 | */ |
| 986 | public URL getResource(String name) { |
| 987 | URL url; |
| 988 | if (parent != null) { |
| 989 | url = parent.getResource(name); |
| 990 | } else { |
| 991 | url = getBootstrapResource(name); |
| 992 | } |
| 993 | if (url == null) { |
| 994 | url = findResource(name); |
| 995 | } |
| 996 | return url; |
| 997 | } |
| 998 | |
| 999 | /** |
| 1000 | * Finds all the resources with the given name. A resource is some data |
| 1001 | * (images, audio, text, etc) that can be accessed by class code in a way |
| 1002 | * that is independent of the location of the code. |
| 1003 | * |
| 1004 | * <p>The name of a resource is a <tt>/</tt>-separated path name that |
| 1005 | * identifies the resource. |
| 1006 | * |
| 1007 | * <p> The search order is described in the documentation for {@link |
| 1008 | * #getResource(String)}. </p> |
| 1009 | * |
| 1010 | * @param name |
| 1011 | * The resource name |
| 1012 | * |
| 1013 | * @return An enumeration of {@link java.net.URL <tt>URL</tt>} objects for |
| 1014 | * the resource. If no resources could be found, the enumeration |
| 1015 | * will be empty. Resources that the class loader doesn't have |
| 1016 | * access to will not be in the enumeration. |
| 1017 | * |
| 1018 | * @throws IOException |
| 1019 | * If I/O errors occur |
| 1020 | * |
| 1021 | * @see #findResources(String) |
| 1022 | * |
| 1023 | * @since 1.2 |
| 1024 | */ |
| 1025 | public Enumeration<URL> getResources(String name) throws IOException { |
| 1026 | Enumeration[] tmp = new Enumeration[2]; |
| 1027 | if (parent != null) { |
| 1028 | tmp[0] = parent.getResources(name); |
| 1029 | } else { |
| 1030 | tmp[0] = getBootstrapResources(name); |
| 1031 | } |
| 1032 | tmp[1] = findResources(name); |
| 1033 | |
| 1034 | return new CompoundEnumeration(tmp); |
| 1035 | } |
| 1036 | |
| 1037 | /** |
| 1038 | * Finds the resource with the given name. Class loader implementations |
| 1039 | * should override this method to specify where to find resources. </p> |
| 1040 | * |
| 1041 | * @param name |
| 1042 | * The resource name |
| 1043 | * |
| 1044 | * @return A <tt>URL</tt> object for reading the resource, or |
| 1045 | * <tt>null</tt> if the resource could not be found |
| 1046 | * |
| 1047 | * @since 1.2 |
| 1048 | */ |
| 1049 | protected URL findResource(String name) { |
| 1050 | return null; |
| 1051 | } |
| 1052 | |
| 1053 | /** |
| 1054 | * Returns an enumeration of {@link java.net.URL <tt>URL</tt>} objects |
| 1055 | * representing all the resources with the given name. Class loader |
| 1056 | * implementations should override this method to specify where to load |
| 1057 | * resources from. </p> |
| 1058 | * |
| 1059 | * @param name |
| 1060 | * The resource name |
| 1061 | * |
| 1062 | * @return An enumeration of {@link java.net.URL <tt>URL</tt>} objects for |
| 1063 | * the resources |
| 1064 | * |
| 1065 | * @throws IOException |
| 1066 | * If I/O errors occur |
| 1067 | * |
| 1068 | * @since 1.2 |
| 1069 | */ |
| 1070 | protected Enumeration<URL> findResources(String name) throws IOException { |
| 1071 | return new CompoundEnumeration(new Enumeration[0]); |
| 1072 | } |
| 1073 | |
| 1074 | /** |
| 1075 | * Find a resource of the specified name from the search path used to load |
| 1076 | * classes. This method locates the resource through the system class |
| 1077 | * loader (see {@link #getSystemClassLoader()}). </p> |
| 1078 | * |
| 1079 | * @param name |
| 1080 | * The resource name |
| 1081 | * |
| 1082 | * @return A {@link java.net.URL <tt>URL</tt>} object for reading the |
| 1083 | * resource, or <tt>null</tt> if the resource could not be found |
| 1084 | * |
| 1085 | * @since 1.1 |
| 1086 | */ |
| 1087 | public static URL getSystemResource(String name) { |
| 1088 | ClassLoader system = getSystemClassLoader(); |
| 1089 | if (system == null) { |
| 1090 | return getBootstrapResource(name); |
| 1091 | } |
| 1092 | return system.getResource(name); |
| 1093 | } |
| 1094 | |
| 1095 | /** |
| 1096 | * Finds all resources of the specified name from the search path used to |
| 1097 | * load classes. The resources thus found are returned as an |
| 1098 | * {@link java.util.Enumeration <tt>Enumeration</tt>} of {@link |
| 1099 | * java.net.URL <tt>URL</tt>} objects. |
| 1100 | * |
| 1101 | * <p> The search order is described in the documentation for {@link |
| 1102 | * #getSystemResource(String)}. </p> |
| 1103 | * |
| 1104 | * @param name |
| 1105 | * The resource name |
| 1106 | * |
| 1107 | * @return An enumeration of resource {@link java.net.URL <tt>URL</tt>} |
| 1108 | * objects |
| 1109 | * |
| 1110 | * @throws IOException |
| 1111 | * If I/O errors occur |
| 1112 | |
| 1113 | * @since 1.2 |
| 1114 | */ |
| 1115 | public static Enumeration<URL> getSystemResources(String name) |
| 1116 | throws IOException |
| 1117 | { |
| 1118 | ClassLoader system = getSystemClassLoader(); |
| 1119 | if (system == null) { |
| 1120 | return getBootstrapResources(name); |
| 1121 | } |
| 1122 | return system.getResources(name); |
| 1123 | } |
| 1124 | |
| 1125 | /** |
| 1126 | * Find resources from the VM's built-in classloader. |
| 1127 | */ |
| 1128 | private static URL getBootstrapResource(String name) { |
| 1129 | URLClassPath ucp = getBootstrapClassPath(); |
| 1130 | Resource res = ucp.getResource(name); |
| 1131 | return res != null ? res.getURL() : null; |
| 1132 | } |
| 1133 | |
| 1134 | /** |
| 1135 | * Find resources from the VM's built-in classloader. |
| 1136 | */ |
| 1137 | private static Enumeration getBootstrapResources(String name) |
| 1138 | throws IOException |
| 1139 | { |
| 1140 | final Enumeration e = getBootstrapClassPath().getResources(name); |
| 1141 | return new Enumeration () { |
| 1142 | public Object nextElement() { |
| 1143 | return ((Resource)e.nextElement()).getURL(); |
| 1144 | } |
| 1145 | public boolean hasMoreElements() { |
| 1146 | return e.hasMoreElements(); |
| 1147 | } |
| 1148 | }; |
| 1149 | } |
| 1150 | |
| 1151 | // Returns the URLClassPath that is used for finding system resources. |
| 1152 | static URLClassPath getBootstrapClassPath() { |
| 1153 | if (bootstrapClassPath == null) { |
| 1154 | bootstrapClassPath = sun.misc.Launcher.getBootstrapClassPath(); |
| 1155 | } |
| 1156 | return bootstrapClassPath; |
| 1157 | } |
| 1158 | |
| 1159 | private static URLClassPath bootstrapClassPath; |
| 1160 | |
| 1161 | /** |
| 1162 | * Returns an input stream for reading the specified resource. |
| 1163 | * |
| 1164 | * <p> The search order is described in the documentation for {@link |
| 1165 | * #getResource(String)}. </p> |
| 1166 | * |
| 1167 | * @param name |
| 1168 | * The resource name |
| 1169 | * |
| 1170 | * @return An input stream for reading the resource, or <tt>null</tt> |
| 1171 | * if the resource could not be found |
| 1172 | * |
| 1173 | * @since 1.1 |
| 1174 | */ |
| 1175 | public InputStream getResourceAsStream(String name) { |
| 1176 | URL url = getResource(name); |
| 1177 | try { |
| 1178 | return url != null ? url.openStream() : null; |
| 1179 | } catch (IOException e) { |
| 1180 | return null; |
| 1181 | } |
| 1182 | } |
| 1183 | |
| 1184 | /** |
| 1185 | * Open for reading, a resource of the specified name from the search path |
| 1186 | * used to load classes. This method locates the resource through the |
| 1187 | * system class loader (see {@link #getSystemClassLoader()}). </p> |
| 1188 | * |
| 1189 | * @param name |
| 1190 | * The resource name |
| 1191 | * |
| 1192 | * @return An input stream for reading the resource, or <tt>null</tt> |
| 1193 | * if the resource could not be found |
| 1194 | * |
| 1195 | * @since 1.1 |
| 1196 | */ |
| 1197 | public static InputStream getSystemResourceAsStream(String name) { |
| 1198 | URL url = getSystemResource(name); |
| 1199 | try { |
| 1200 | return url != null ? url.openStream() : null; |
| 1201 | } catch (IOException e) { |
| 1202 | return null; |
| 1203 | } |
| 1204 | } |
| 1205 | |
| 1206 | |
| 1207 | // -- Hierarchy -- |
| 1208 | |
| 1209 | /** |
| 1210 | * Returns the parent class loader for delegation. Some implementations may |
| 1211 | * use <tt>null</tt> to represent the bootstrap class loader. This method |
| 1212 | * will return <tt>null</tt> in such implementations if this class loader's |
| 1213 | * parent is the bootstrap class loader. |
| 1214 | * |
| 1215 | * <p> If a security manager is present, and the invoker's class loader is |
| 1216 | * not <tt>null</tt> and is not an ancestor of this class loader, then this |
| 1217 | * method invokes the security manager's {@link |
| 1218 | * SecurityManager#checkPermission(java.security.Permission) |
| 1219 | * <tt>checkPermission</tt>} method with a {@link |
| 1220 | * RuntimePermission#RuntimePermission(String) |
| 1221 | * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify |
| 1222 | * access to the parent class loader is permitted. If not, a |
| 1223 | * <tt>SecurityException</tt> will be thrown. </p> |
| 1224 | * |
| 1225 | * @return The parent <tt>ClassLoader</tt> |
| 1226 | * |
| 1227 | * @throws SecurityException |
| 1228 | * If a security manager exists and its <tt>checkPermission</tt> |
| 1229 | * method doesn't allow access to this class loader's parent class |
| 1230 | * loader. |
| 1231 | * |
| 1232 | * @since 1.2 |
| 1233 | */ |
| 1234 | public final ClassLoader getParent() { |
| 1235 | if (parent == null) |
| 1236 | return null; |
| 1237 | SecurityManager sm = System.getSecurityManager(); |
| 1238 | if (sm != null) { |
| 1239 | ClassLoader ccl = getCallerClassLoader(); |
| 1240 | if (ccl != null && !isAncestor(ccl)) { |
| 1241 | sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); |
| 1242 | } |
| 1243 | } |
| 1244 | return parent; |
| 1245 | } |
| 1246 | |
| 1247 | /** |
| 1248 | * Returns the system class loader for delegation. This is the default |
| 1249 | * delegation parent for new <tt>ClassLoader</tt> instances, and is |
| 1250 | * typically the class loader used to start the application. |
| 1251 | * |
| 1252 | * <p> This method is first invoked early in the runtime's startup |
| 1253 | * sequence, at which point it creates the system class loader and sets it |
| 1254 | * as the context class loader of the invoking <tt>Thread</tt>. |
| 1255 | * |
| 1256 | * <p> The default system class loader is an implementation-dependent |
| 1257 | * instance of this class. |
| 1258 | * |
| 1259 | * <p> If the system property "<tt>java.system.class.loader</tt>" is defined |
| 1260 | * when this method is first invoked then the value of that property is |
| 1261 | * taken to be the name of a class that will be returned as the system |
| 1262 | * class loader. The class is loaded using the default system class loader |
| 1263 | * and must define a public constructor that takes a single parameter of |
| 1264 | * type <tt>ClassLoader</tt> which is used as the delegation parent. An |
| 1265 | * instance is then created using this constructor with the default system |
| 1266 | * class loader as the parameter. The resulting class loader is defined |
| 1267 | * to be the system class loader. |
| 1268 | * |
| 1269 | * <p> If a security manager is present, and the invoker's class loader is |
| 1270 | * not <tt>null</tt> and the invoker's class loader is not the same as or |
| 1271 | * an ancestor of the system class loader, then this method invokes the |
| 1272 | * security manager's {@link |
| 1273 | * SecurityManager#checkPermission(java.security.Permission) |
| 1274 | * <tt>checkPermission</tt>} method with a {@link |
| 1275 | * RuntimePermission#RuntimePermission(String) |
| 1276 | * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify |
| 1277 | * access to the system class loader. If not, a |
| 1278 | * <tt>SecurityException</tt> will be thrown. </p> |
| 1279 | * |
| 1280 | * @return The system <tt>ClassLoader</tt> for delegation, or |
| 1281 | * <tt>null</tt> if none |
| 1282 | * |
| 1283 | * @throws SecurityException |
| 1284 | * If a security manager exists and its <tt>checkPermission</tt> |
| 1285 | * method doesn't allow access to the system class loader. |
| 1286 | * |
| 1287 | * @throws IllegalStateException |
| 1288 | * If invoked recursively during the construction of the class |
| 1289 | * loader specified by the "<tt>java.system.class.loader</tt>" |
| 1290 | * property. |
| 1291 | * |
| 1292 | * @throws Error |
| 1293 | * If the system property "<tt>java.system.class.loader</tt>" |
| 1294 | * is defined but the named class could not be loaded, the |
| 1295 | * provider class does not define the required constructor, or an |
| 1296 | * exception is thrown by that constructor when it is invoked. The |
| 1297 | * underlying cause of the error can be retrieved via the |
| 1298 | * {@link Throwable#getCause()} method. |
| 1299 | * |
| 1300 | * @revised 1.4 |
| 1301 | */ |
| 1302 | public static ClassLoader getSystemClassLoader() { |
| 1303 | initSystemClassLoader(); |
| 1304 | if (scl == null) { |
| 1305 | return null; |
| 1306 | } |
| 1307 | SecurityManager sm = System.getSecurityManager(); |
| 1308 | if (sm != null) { |
| 1309 | ClassLoader ccl = getCallerClassLoader(); |
| 1310 | if (ccl != null && ccl != scl && !scl.isAncestor(ccl)) { |
| 1311 | sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); |
| 1312 | } |
| 1313 | } |
| 1314 | return scl; |
| 1315 | } |
| 1316 | |
| 1317 | private static synchronized void initSystemClassLoader() { |
| 1318 | if (!sclSet) { |
| 1319 | if (scl != null) |
| 1320 | throw new IllegalStateException("recursive invocation"); |
| 1321 | sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); |
| 1322 | if (l != null) { |
| 1323 | Throwable oops = null; |
| 1324 | scl = l.getClassLoader(); |
| 1325 | try { |
| 1326 | PrivilegedExceptionAction a; |
| 1327 | a = new SystemClassLoaderAction(scl); |
| 1328 | scl = (ClassLoader) AccessController.doPrivileged(a); |
| 1329 | } catch (PrivilegedActionException pae) { |
| 1330 | oops = pae.getCause(); |
| 1331 | if (oops instanceof InvocationTargetException) { |
| 1332 | oops = oops.getCause(); |
| 1333 | } |
| 1334 | } |
| 1335 | if (oops != null) { |
| 1336 | if (oops instanceof Error) { |
| 1337 | throw (Error) oops; |
| 1338 | } else { |
| 1339 | // wrap the exception |
| 1340 | throw new Error(oops); |
| 1341 | } |
| 1342 | } |
| 1343 | } |
| 1344 | sclSet = true; |
| 1345 | } |
| 1346 | } |
| 1347 | |
| 1348 | // Returns true if the specified class loader can be found in this class |
| 1349 | // loader's delegation chain. |
| 1350 | boolean isAncestor(ClassLoader cl) { |
| 1351 | ClassLoader acl = this; |
| 1352 | do { |
| 1353 | acl = acl.parent; |
| 1354 | if (cl == acl) { |
| 1355 | return true; |
| 1356 | } |
| 1357 | } while (acl != null); |
| 1358 | return false; |
| 1359 | } |
| 1360 | |
| 1361 | // Returns the invoker's class loader, or null if none. |
| 1362 | // NOTE: This must always be invoked when there is exactly one intervening |
| 1363 | // frame from the core libraries on the stack between this method's |
| 1364 | // invocation and the desired invoker. |
| 1365 | static ClassLoader getCallerClassLoader() { |
| 1366 | // NOTE use of more generic Reflection.getCallerClass() |
| 1367 | Class caller = Reflection.getCallerClass(3); |
| 1368 | // This can be null if the VM is requesting it |
| 1369 | if (caller == null) { |
| 1370 | return null; |
| 1371 | } |
| 1372 | // Circumvent security check since this is package-private |
| 1373 | return caller.getClassLoader0(); |
| 1374 | } |
| 1375 | |
| 1376 | // The class loader for the system |
| 1377 | private static ClassLoader scl; |
| 1378 | |
| 1379 | // Set to true once the system class loader has been set |
| 1380 | private static boolean sclSet; |
| 1381 | |
| 1382 | |
| 1383 | // -- Package -- |
| 1384 | |
| 1385 | /** |
| 1386 | * Defines a package by name in this <tt>ClassLoader</tt>. This allows |
| 1387 | * class loaders to define the packages for their classes. Packages must |
| 1388 | * be created before the class is defined, and package names must be |
| 1389 | * unique within a class loader and cannot be redefined or changed once |
| 1390 | * created. </p> |
| 1391 | * |
| 1392 | * @param name |
| 1393 | * The package name |
| 1394 | * |
| 1395 | * @param specTitle |
| 1396 | * The specification title |
| 1397 | * |
| 1398 | * @param specVersion |
| 1399 | * The specification version |
| 1400 | * |
| 1401 | * @param specVendor |
| 1402 | * The specification vendor |
| 1403 | * |
| 1404 | * @param implTitle |
| 1405 | * The implementation title |
| 1406 | * |
| 1407 | * @param implVersion |
| 1408 | * The implementation version |
| 1409 | * |
| 1410 | * @param implVendor |
| 1411 | * The implementation vendor |
| 1412 | * |
| 1413 | * @param sealBase |
| 1414 | * If not <tt>null</tt>, then this package is sealed with |
| 1415 | * respect to the given code source {@link java.net.URL |
| 1416 | * <tt>URL</tt>} object. Otherwise, the package is not sealed. |
| 1417 | * |
| 1418 | * @return The newly defined <tt>Package</tt> object |
| 1419 | * |
| 1420 | * @throws IllegalArgumentException |
| 1421 | * If package name duplicates an existing package either in this |
| 1422 | * class loader or one of its ancestors |
| 1423 | * |
| 1424 | * @since 1.2 |
| 1425 | */ |
| 1426 | protected Package definePackage(String name, String specTitle, |
| 1427 | String specVersion, String specVendor, |
| 1428 | String implTitle, String implVersion, |
| 1429 | String implVendor, URL sealBase) |
| 1430 | throws IllegalArgumentException |
| 1431 | { |
| 1432 | synchronized (packages) { |
| 1433 | Package pkg = getPackage(name); |
| 1434 | if (pkg != null) { |
| 1435 | throw new IllegalArgumentException(name); |
| 1436 | } |
| 1437 | pkg = new Package(name, specTitle, specVersion, specVendor, |
| 1438 | implTitle, implVersion, implVendor, |
| 1439 | sealBase, this); |
| 1440 | packages.put(name, pkg); |
| 1441 | return pkg; |
| 1442 | } |
| 1443 | } |
| 1444 | |
| 1445 | /** |
| 1446 | * Returns a <tt>Package</tt> that has been defined by this class loader |
| 1447 | * or any of its ancestors. </p> |
| 1448 | * |
| 1449 | * @param name |
| 1450 | * The package name |
| 1451 | * |
| 1452 | * @return The <tt>Package</tt> corresponding to the given name, or |
| 1453 | * <tt>null</tt> if not found |
| 1454 | * |
| 1455 | * @since 1.2 |
| 1456 | */ |
| 1457 | protected Package getPackage(String name) { |
| 1458 | synchronized (packages) { |
| 1459 | Package pkg = (Package)packages.get(name); |
| 1460 | if (pkg == null) { |
| 1461 | if (parent != null) { |
| 1462 | pkg = parent.getPackage(name); |
| 1463 | } else { |
| 1464 | pkg = Package.getSystemPackage(name); |
| 1465 | } |
| 1466 | if (pkg != null) { |
| 1467 | packages.put(name, pkg); |
| 1468 | } |
| 1469 | } |
| 1470 | return pkg; |
| 1471 | } |
| 1472 | } |
| 1473 | |
| 1474 | /** |
| 1475 | * Returns all of the <tt>Packages</tt> defined by this class loader and |
| 1476 | * its ancestors. </p> |
| 1477 | * |
| 1478 | * @return The array of <tt>Package</tt> objects defined by this |
| 1479 | * <tt>ClassLoader</tt> |
| 1480 | * |
| 1481 | * @since 1.2 |
| 1482 | */ |
| 1483 | protected Package[] getPackages() { |
| 1484 | Map map; |
| 1485 | synchronized (packages) { |
| 1486 | map = (Map)packages.clone(); |
| 1487 | } |
| 1488 | Package[] pkgs; |
| 1489 | if (parent != null) { |
| 1490 | pkgs = parent.getPackages(); |
| 1491 | } else { |
| 1492 | pkgs = Package.getSystemPackages(); |
| 1493 | } |
| 1494 | if (pkgs != null) { |
| 1495 | for (int i = 0; i < pkgs.length; i++) { |
| 1496 | String pkgName = pkgs[i].getName(); |
| 1497 | if (map.get(pkgName) == null) { |
| 1498 | map.put(pkgName, pkgs[i]); |
| 1499 | } |
| 1500 | } |
| 1501 | } |
| 1502 | return (Package[])map.values().toArray(new Package[map.size()]); |
| 1503 | } |
| 1504 | |
| 1505 | |
| 1506 | // -- Native library access -- |
| 1507 | |
| 1508 | /** |
| 1509 | * Returns the absolute path name of a native library. The VM invokes this |
| 1510 | * method to locate the native libraries that belong to classes loaded with |
| 1511 | * this class loader. If this method returns <tt>null</tt>, the VM |
| 1512 | * searches the library along the path specified as the |
| 1513 | * "<tt>java.library.path</tt>" property. </p> |
| 1514 | * |
| 1515 | * @param libname |
| 1516 | * The library name |
| 1517 | * |
| 1518 | * @return The absolute path of the native library |
| 1519 | * |
| 1520 | * @see System#loadLibrary(String) |
| 1521 | * @see System#mapLibraryName(String) |
| 1522 | * |
| 1523 | * @since 1.2 |
| 1524 | */ |
| 1525 | protected String findLibrary(String libname) { |
| 1526 | return null; |
| 1527 | } |
| 1528 | |
| 1529 | /** |
| 1530 | * The inner class NativeLibrary denotes a loaded native library instance. |
| 1531 | * Every classloader contains a vector of loaded native libraries in the |
| 1532 | * private field <tt>nativeLibraries</tt>. The native libraries loaded |
| 1533 | * into the system are entered into the <tt>systemNativeLibraries</tt> |
| 1534 | * vector. |
| 1535 | * |
| 1536 | * <p> Every native library requires a particular version of JNI. This is |
| 1537 | * denoted by the private <tt>jniVersion</tt> field. This field is set by |
| 1538 | * the VM when it loads the library, and used by the VM to pass the correct |
| 1539 | * version of JNI to the native methods. </p> |
| 1540 | * |
| 1541 | * @see ClassLoader |
| 1542 | * @since 1.2 |
| 1543 | */ |
| 1544 | static class NativeLibrary { |
| 1545 | // opaque handle to native library, used in native code. |
| 1546 | long handle; |
| 1547 | // the version of JNI environment the native library requires. |
| 1548 | private int jniVersion; |
| 1549 | // the class from which the library is loaded, also indicates |
| 1550 | // the loader this native library belongs. |
| 1551 | private Class fromClass; |
| 1552 | // the canonicalized name of the native library. |
| 1553 | String name; |
| 1554 | |
| 1555 | native void load(String name); |
| 1556 | native long find(String name); |
| 1557 | native void unload(); |
| 1558 | |
| 1559 | public NativeLibrary(Class fromClass, String name) { |
| 1560 | this.name = name; |
| 1561 | this.fromClass = fromClass; |
| 1562 | } |
| 1563 | |
| 1564 | protected void finalize() { |
| 1565 | synchronized (loadedLibraryNames) { |
| 1566 | if (fromClass.getClassLoader() != null && handle != 0) { |
| 1567 | /* remove the native library name */ |
| 1568 | int size = loadedLibraryNames.size(); |
| 1569 | for (int i = 0; i < size; i++) { |
| 1570 | if (name.equals(loadedLibraryNames.elementAt(i))) { |
| 1571 | loadedLibraryNames.removeElementAt(i); |
| 1572 | break; |
| 1573 | } |
| 1574 | } |
| 1575 | /* unload the library. */ |
| 1576 | ClassLoader.nativeLibraryContext.push(this); |
| 1577 | try { |
| 1578 | unload(); |
| 1579 | } finally { |
| 1580 | ClassLoader.nativeLibraryContext.pop(); |
| 1581 | } |
| 1582 | } |
| 1583 | } |
| 1584 | } |
| 1585 | // Invoked in the VM to determine the context class in |
| 1586 | // JNI_Load/JNI_Unload |
| 1587 | static Class getFromClass() { |
| 1588 | return ((NativeLibrary) |
| 1589 | (ClassLoader.nativeLibraryContext.peek())).fromClass; |
| 1590 | } |
| 1591 | } |
| 1592 | |
| 1593 | // The "default" domain. Set as the default ProtectionDomain on newly |
| 1594 | // created classes. |
| 1595 | private ProtectionDomain defaultDomain = null; |
| 1596 | |
| 1597 | // Returns (and initializes) the default domain. |
| 1598 | private synchronized ProtectionDomain getDefaultDomain() { |
| 1599 | if (defaultDomain == null) { |
| 1600 | CodeSource cs = |
| 1601 | new CodeSource(null, (java.security.cert.Certificate[]) null); |
| 1602 | defaultDomain = new ProtectionDomain(cs, null, this, null); |
| 1603 | } |
| 1604 | return defaultDomain; |
| 1605 | } |
| 1606 | |
| 1607 | // All native library names we've loaded. |
| 1608 | private static Vector loadedLibraryNames = new Vector(); |
| 1609 | // Native libraries belonging to system classes. |
| 1610 | private static Vector systemNativeLibraries = new Vector(); |
| 1611 | // Native libraries associated with the class loader. |
| 1612 | private Vector nativeLibraries = new Vector(); |
| 1613 | |
| 1614 | // native libraries being loaded/unloaded. |
| 1615 | private static Stack nativeLibraryContext = new Stack(); |
| 1616 | |
| 1617 | // The paths searched for libraries |
| 1618 | static private String usr_paths[]; |
| 1619 | static private String sys_paths[]; |
| 1620 | |
| 1621 | private static String[] initializePath(String propname) { |
| 1622 | String ldpath = System.getProperty(propname, ""); |
| 1623 | String ps = File.pathSeparator; |
| 1624 | int ldlen = ldpath.length(); |
| 1625 | int i, j, n; |
| 1626 | // Count the separators in the path |
| 1627 | i = ldpath.indexOf(ps); |
| 1628 | n = 0; |
| 1629 | while (i >= 0) { |
| 1630 | n++; |
| 1631 | i = ldpath.indexOf(ps, i + 1); |
| 1632 | } |
| 1633 | |
| 1634 | // allocate the array of paths - n :'s = n + 1 path elements |
| 1635 | String[] paths = new String[n + 1]; |
| 1636 | |
| 1637 | // Fill the array with paths from the ldpath |
| 1638 | n = i = 0; |
| 1639 | j = ldpath.indexOf(ps); |
| 1640 | while (j >= 0) { |
| 1641 | if (j - i > 0) { |
| 1642 | paths[n++] = ldpath.substring(i, j); |
| 1643 | } else if (j - i == 0) { |
| 1644 | paths[n++] = "."; |
| 1645 | } |
| 1646 | i = j + 1; |
| 1647 | j = ldpath.indexOf(ps, i); |
| 1648 | } |
| 1649 | paths[n] = ldpath.substring(i, ldlen); |
| 1650 | return paths; |
| 1651 | } |
| 1652 | |
| 1653 | // Invoked in the java.lang.Runtime class to implement load and loadLibrary. |
| 1654 | static void loadLibrary(Class fromClass, String name, |
| 1655 | boolean isAbsolute) { |
| 1656 | ClassLoader loader = |
| 1657 | (fromClass == null) ? null : fromClass.getClassLoader(); |
| 1658 | if (sys_paths == null) { |
| 1659 | usr_paths = initializePath("java.library.path"); |
| 1660 | sys_paths = initializePath("sun.boot.library.path"); |
| 1661 | } |
| 1662 | if (isAbsolute) { |
| 1663 | if (loadLibrary0(fromClass, new File(name))) { |
| 1664 | return; |
| 1665 | } |
| 1666 | throw new UnsatisfiedLinkError("Can't load library: " + name); |
| 1667 | } |
| 1668 | if (loader != null) { |
| 1669 | String libfilename = loader.findLibrary(name); |
| 1670 | if (libfilename != null) { |
| 1671 | File libfile = new File(libfilename); |
| 1672 | if (!libfile.isAbsolute()) { |
| 1673 | throw new UnsatisfiedLinkError( |
| 1674 | "ClassLoader.findLibrary failed to return an absolute path: " + libfilename); |
| 1675 | } |
| 1676 | if (loadLibrary0(fromClass, libfile)) { |
| 1677 | return; |
| 1678 | } |
| 1679 | throw new UnsatisfiedLinkError("Can't load " + libfilename); |
| 1680 | } |
| 1681 | } |
| 1682 | for (int i = 0 ; i < sys_paths.length ; i++) { |
| 1683 | File libfile = new File(sys_paths[i], System.mapLibraryName(name)); |
| 1684 | if (loadLibrary0(fromClass, libfile)) { |
| 1685 | return; |
| 1686 | } |
| 1687 | } |
| 1688 | if (loader != null) { |
| 1689 | for (int i = 0 ; i < usr_paths.length ; i++) { |
| 1690 | File libfile = new File(usr_paths[i], |
| 1691 | System.mapLibraryName(name)); |
| 1692 | if (loadLibrary0(fromClass, libfile)) { |
| 1693 | return; |
| 1694 | } |
| 1695 | } |
| 1696 | } |
| 1697 | // Oops, it failed |
| 1698 | throw new UnsatisfiedLinkError("no " + name + " in java.library.path"); |
| 1699 | } |
| 1700 | |
| 1701 | private static boolean loadLibrary0(Class fromClass, final File file) { |
| 1702 | Boolean exists = (Boolean) |
| 1703 | AccessController.doPrivileged(new PrivilegedAction() { |
| 1704 | public Object run() { |
| 1705 | return new Boolean(file.exists()); |
| 1706 | } |
| 1707 | }); |
| 1708 | if (!exists.booleanValue()) { |
| 1709 | return false; |
| 1710 | } |
| 1711 | String name; |
| 1712 | try { |
| 1713 | name = file.getCanonicalPath(); |
| 1714 | } catch (IOException e) { |
| 1715 | return false; |
| 1716 | } |
| 1717 | ClassLoader loader = |
| 1718 | (fromClass == null) ? null : fromClass.getClassLoader(); |
| 1719 | Vector libs = |
| 1720 | loader != null ? loader.nativeLibraries : systemNativeLibraries; |
| 1721 | synchronized (libs) { |
| 1722 | int size = libs.size(); |
| 1723 | for (int i = 0; i < size; i++) { |
| 1724 | NativeLibrary lib = (NativeLibrary)libs.elementAt(i); |
| 1725 | if (name.equals(lib.name)) { |
| 1726 | return true; |
| 1727 | } |
| 1728 | } |
| 1729 | |
| 1730 | synchronized (loadedLibraryNames) { |
| 1731 | if (loadedLibraryNames.contains(name)) { |
| 1732 | throw new UnsatisfiedLinkError |
| 1733 | ("Native Library " + |
| 1734 | name + |
| 1735 | " already loaded in another classloader"); |
| 1736 | } |
| 1737 | /* If the library is being loaded (must be by the same thread, |
| 1738 | * because Runtime.load and Runtime.loadLibrary are |
| 1739 | * synchronous). The reason is can occur is that the JNI_OnLoad |
| 1740 | * function can cause another loadLibrary invocation. |
| 1741 | * |
| 1742 | * Thus we can use a static stack to hold the list of libraries |
| 1743 | * we are loading. |
| 1744 | * |
| 1745 | * If there is a pending load operation for the library, we |
| 1746 | * immediately return success; otherwise, we raise |
| 1747 | * UnsatisfiedLinkError. |
| 1748 | */ |
| 1749 | int n = nativeLibraryContext.size(); |
| 1750 | for (int i = 0; i < n; i++) { |
| 1751 | NativeLibrary lib = (NativeLibrary) |
| 1752 | nativeLibraryContext.elementAt(i); |
| 1753 | if (name.equals(lib.name)) { |
| 1754 | if (loader == lib.fromClass.getClassLoader()) { |
| 1755 | return true; |
| 1756 | } else { |
| 1757 | throw new UnsatisfiedLinkError |
| 1758 | ("Native Library " + |
| 1759 | name + |
| 1760 | " is being loaded in another classloader"); |
| 1761 | } |
| 1762 | } |
| 1763 | } |
| 1764 | NativeLibrary lib = new NativeLibrary(fromClass, name); |
| 1765 | nativeLibraryContext.push(lib); |
| 1766 | try { |
| 1767 | lib.load(name); |
| 1768 | } finally { |
| 1769 | nativeLibraryContext.pop(); |
| 1770 | } |
| 1771 | if (lib.handle != 0) { |
| 1772 | loadedLibraryNames.addElement(name); |
| 1773 | libs.addElement(lib); |
| 1774 | return true; |
| 1775 | } |
| 1776 | return false; |
| 1777 | } |
| 1778 | } |
| 1779 | } |
| 1780 | |
| 1781 | // Invoked in the VM class linking code. |
| 1782 | static long findNative(ClassLoader loader, String name) { |
| 1783 | Vector libs = |
| 1784 | loader != null ? loader.nativeLibraries : systemNativeLibraries; |
| 1785 | synchronized (libs) { |
| 1786 | int size = libs.size(); |
| 1787 | for (int i = 0; i < size; i++) { |
| 1788 | NativeLibrary lib = (NativeLibrary)libs.elementAt(i); |
| 1789 | long entry = lib.find(name); |
| 1790 | if (entry != 0) |
| 1791 | return entry; |
| 1792 | } |
| 1793 | } |
| 1794 | return 0; |
| 1795 | } |
| 1796 | |
| 1797 | |
| 1798 | // -- Assertion management -- |
| 1799 | |
| 1800 | // The default toggle for assertion checking. |
| 1801 | private boolean defaultAssertionStatus = false; |
| 1802 | |
| 1803 | // Maps String packageName to Boolean package default assertion status Note |
| 1804 | // that the default package is placed under a null map key. If this field |
| 1805 | // is null then we are delegating assertion status queries to the VM, i.e., |
| 1806 | // none of this ClassLoader's assertion status modification methods have |
| 1807 | // been invoked. |
| 1808 | private Map packageAssertionStatus = null; |
| 1809 | |
| 1810 | // Maps String fullyQualifiedClassName to Boolean assertionStatus If this |
| 1811 | // field is null then we are delegating assertion status queries to the VM, |
| 1812 | // i.e., none of this ClassLoader's assertion status modification methods |
| 1813 | // have been invoked. |
| 1814 | Map classAssertionStatus = null; |
| 1815 | |
| 1816 | /** |
| 1817 | * Sets the default assertion status for this class loader. This setting |
| 1818 | * determines whether classes loaded by this class loader and initialized |
| 1819 | * in the future will have assertions enabled or disabled by default. |
| 1820 | * This setting may be overridden on a per-package or per-class basis by |
| 1821 | * invoking {@link #setPackageAssertionStatus(String, boolean)} or {@link |
| 1822 | * #setClassAssertionStatus(String, boolean)}. </p> |
| 1823 | * |
| 1824 | * @param enabled |
| 1825 | * <tt>true</tt> if classes loaded by this class loader will |
| 1826 | * henceforth have assertions enabled by default, <tt>false</tt> |
| 1827 | * if they will have assertions disabled by default. |
| 1828 | * |
| 1829 | * @since 1.4 |
| 1830 | */ |
| 1831 | public synchronized void setDefaultAssertionStatus(boolean enabled) { |
| 1832 | if (classAssertionStatus == null) |
| 1833 | initializeJavaAssertionMaps(); |
| 1834 | |
| 1835 | defaultAssertionStatus = enabled; |
| 1836 | } |
| 1837 | |
| 1838 | /** |
| 1839 | * Sets the package default assertion status for the named package. The |
| 1840 | * package default assertion status determines the assertion status for |
| 1841 | * classes initialized in the future that belong to the named package or |
| 1842 | * any of its "subpackages". |
| 1843 | * |
| 1844 | * <p> A subpackage of a package named p is any package whose name begins |
| 1845 | * with "<tt>p.</tt>". For example, <tt>javax.swing.text</tt> is a |
| 1846 | * subpackage of <tt>javax.swing</tt>, and both <tt>java.util</tt> and |
| 1847 | * <tt>java.lang.reflect</tt> are subpackages of <tt>java</tt>. |
| 1848 | * |
| 1849 | * <p> In the event that multiple package defaults apply to a given class, |
| 1850 | * the package default pertaining to the most specific package takes |
| 1851 | * precedence over the others. For example, if <tt>javax.lang</tt> and |
| 1852 | * <tt>javax.lang.reflect</tt> both have package defaults associated with |
| 1853 | * them, the latter package default applies to classes in |
| 1854 | * <tt>javax.lang.reflect</tt>. |
| 1855 | * |
| 1856 | * <p> Package defaults take precedence over the class loader's default |
| 1857 | * assertion status, and may be overridden on a per-class basis by invoking |
| 1858 | * {@link #setClassAssertionStatus(String, boolean)}. </p> |
| 1859 | * |
| 1860 | * @param packageName |
| 1861 | * The name of the package whose package default assertion status |
| 1862 | * is to be set. A <tt>null</tt> value indicates the unnamed |
| 1863 | * package that is "current" |
| 1864 | * (<a href="http://java.sun.com/docs/books/jls/">Java Language |
| 1865 | * Specification</a>, section 7.4.2). |
| 1866 | * |
| 1867 | * @param enabled |
| 1868 | * <tt>true</tt> if classes loaded by this classloader and |
| 1869 | * belonging to the named package or any of its subpackages will |
| 1870 | * have assertions enabled by default, <tt>false</tt> if they will |
| 1871 | * have assertions disabled by default. |
| 1872 | * |
| 1873 | * @since 1.4 |
| 1874 | */ |
| 1875 | public synchronized void setPackageAssertionStatus(String packageName, |
| 1876 | boolean enabled) |
| 1877 | { |
| 1878 | if (packageAssertionStatus == null) |
| 1879 | initializeJavaAssertionMaps(); |
| 1880 | |
| 1881 | packageAssertionStatus.put(packageName, Boolean.valueOf(enabled)); |
| 1882 | } |
| 1883 | |
| 1884 | /** |
| 1885 | * Sets the desired assertion status for the named top-level class in this |
| 1886 | * class loader and any nested classes contained therein. This setting |
| 1887 | * takes precedence over the class loader's default assertion status, and |
| 1888 | * over any applicable per-package default. This method has no effect if |
| 1889 | * the named class has already been initialized. (Once a class is |
| 1890 | * initialized, its assertion status cannot change.) |
| 1891 | * |
| 1892 | * <p> If the named class is not a top-level class, this invocation will |
| 1893 | * have no effect on the actual assertion status of any class. </p> |
| 1894 | * |
| 1895 | * @param className |
| 1896 | * The fully qualified class name of the top-level class whose |
| 1897 | * assertion status is to be set. |
| 1898 | * |
| 1899 | * @param enabled |
| 1900 | * <tt>true</tt> if the named class is to have assertions |
| 1901 | * enabled when (and if) it is initialized, <tt>false</tt> if the |
| 1902 | * class is to have assertions disabled. |
| 1903 | * |
| 1904 | * @since 1.4 |
| 1905 | */ |
| 1906 | public synchronized void setClassAssertionStatus(String className, |
| 1907 | boolean enabled) |
| 1908 | { |
| 1909 | if (classAssertionStatus == null) |
| 1910 | initializeJavaAssertionMaps(); |
| 1911 | |
| 1912 | classAssertionStatus.put(className, Boolean.valueOf(enabled)); |
| 1913 | } |
| 1914 | |
| 1915 | /** |
| 1916 | * Sets the default assertion status for this class loader to |
| 1917 | * <tt>false</tt> and discards any package defaults or class assertion |
| 1918 | * status settings associated with the class loader. This method is |
| 1919 | * provided so that class loaders can be made to ignore any command line or |
| 1920 | * persistent assertion status settings and "start with a clean slate." |
| 1921 | * </p> |
| 1922 | * |
| 1923 | * @since 1.4 |
| 1924 | */ |
| 1925 | public synchronized void clearAssertionStatus() { |
| 1926 | /* |
| 1927 | * Whether or not "Java assertion maps" are initialized, set |
| 1928 | * them to empty maps, effectively ignoring any present settings. |
| 1929 | */ |
| 1930 | classAssertionStatus = new HashMap(); |
| 1931 | packageAssertionStatus = new HashMap(); |
| 1932 | |
| 1933 | defaultAssertionStatus = false; |
| 1934 | } |
| 1935 | |
| 1936 | /** |
| 1937 | * Returns the assertion status that would be assigned to the specified |
| 1938 | * class if it were to be initialized at the time this method is invoked. |
| 1939 | * If the named class has had its assertion status set, the most recent |
| 1940 | * setting will be returned; otherwise, if any package default assertion |
| 1941 | * status pertains to this class, the most recent setting for the most |
| 1942 | * specific pertinent package default assertion status is returned; |
| 1943 | * otherwise, this class loader's default assertion status is returned. |
| 1944 | * </p> |
| 1945 | * |
| 1946 | * @param className |
| 1947 | * The fully qualified class name of the class whose desired |
| 1948 | * assertion status is being queried. |
| 1949 | * |
| 1950 | * @return The desired assertion status of the specified class. |
| 1951 | * |
| 1952 | * @see #setClassAssertionStatus(String, boolean) |
| 1953 | * @see #setPackageAssertionStatus(String, boolean) |
| 1954 | * @see #setDefaultAssertionStatus(boolean) |
| 1955 | * |
| 1956 | * @since 1.4 |
| 1957 | */ |
| 1958 | synchronized boolean desiredAssertionStatus(String className) { |
| 1959 | Boolean result; |
| 1960 | |
| 1961 | // assert classAssertionStatus != null; |
| 1962 | // assert packageAssertionStatus != null; |
| 1963 | |
| 1964 | // Check for a class entry |
| 1965 | result = (Boolean)classAssertionStatus.get(className); |
| 1966 | if (result != null) |
| 1967 | return result.booleanValue(); |
| 1968 | |
| 1969 | // Check for most specific package entry |
| 1970 | int dotIndex = className.lastIndexOf("."); |
| 1971 | if (dotIndex < 0) { // default package |
| 1972 | result = (Boolean)packageAssertionStatus.get(null); |
| 1973 | if (result != null) |
| 1974 | return result.booleanValue(); |
| 1975 | } |
| 1976 | while(dotIndex > 0) { |
| 1977 | className = className.substring(0, dotIndex); |
| 1978 | result = (Boolean)packageAssertionStatus.get(className); |
| 1979 | if (result != null) |
| 1980 | return result.booleanValue(); |
| 1981 | dotIndex = className.lastIndexOf(".", dotIndex-1); |
| 1982 | } |
| 1983 | |
| 1984 | // Return the classloader default |
| 1985 | return defaultAssertionStatus; |
| 1986 | } |
| 1987 | |
| 1988 | // Set up the assertions with information provided by the VM. |
| 1989 | private void initializeJavaAssertionMaps() { |
| 1990 | // assert Thread.holdsLock(this); |
| 1991 | |
| 1992 | classAssertionStatus = new HashMap(); |
| 1993 | packageAssertionStatus = new HashMap(); |
| 1994 | AssertionStatusDirectives directives = retrieveDirectives(); |
| 1995 | |
| 1996 | for(int i = 0; i < directives.classes.length; i++) |
| 1997 | classAssertionStatus.put(directives.classes[i], |
| 1998 | Boolean.valueOf(directives.classEnabled[i])); |
| 1999 | |
| 2000 | for(int i = 0; i < directives.packages.length; i++) |
| 2001 | packageAssertionStatus.put(directives.packages[i], |
| 2002 | Boolean.valueOf(directives.packageEnabled[i])); |
| 2003 | |
| 2004 | defaultAssertionStatus = directives.deflt; |
| 2005 | } |
| 2006 | |
| 2007 | // Retrieves the assertion directives from the VM. |
| 2008 | private static native AssertionStatusDirectives retrieveDirectives(); |
| 2009 | } |
| 2010 | |
| 2011 | |
| 2012 | class SystemClassLoaderAction implements PrivilegedExceptionAction { |
| 2013 | private ClassLoader parent; |
| 2014 | |
| 2015 | SystemClassLoaderAction(ClassLoader parent) { |
| 2016 | this.parent = parent; |
| 2017 | } |
| 2018 | |
| 2019 | public Object run() throws Exception { |
| 2020 | ClassLoader sys; |
| 2021 | Constructor ctor; |
| 2022 | Class c; |
| 2023 | Class cp[] = { ClassLoader.class }; |
| 2024 | Object params[] = { parent }; |
| 2025 | |
| 2026 | String cls = System.getProperty("java.system.class.loader"); |
| 2027 | if (cls == null) { |
| 2028 | return parent; |
| 2029 | } |
| 2030 | |
| 2031 | c = Class.forName(cls, true, parent); |
| 2032 | ctor = c.getDeclaredConstructor(cp); |
| 2033 | sys = (ClassLoader) ctor.newInstance(params); |
| 2034 | Thread.currentThread().setContextClassLoader(sys); |
| 2035 | return sys; |
| 2036 | } |
| 2037 | } |