|
1 /* |
|
2 * Copyright 1997-2007 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 |
|
26 package java.net; |
|
27 |
|
28 import java.lang.reflect.Method; |
|
29 import java.lang.reflect.Modifier; |
|
30 import java.io.File; |
|
31 import java.io.FilePermission; |
|
32 import java.io.InputStream; |
|
33 import java.io.IOException; |
|
34 import java.net.URL; |
|
35 import java.net.URLConnection; |
|
36 import java.net.URLStreamHandlerFactory; |
|
37 import java.util.Enumeration; |
|
38 import java.util.NoSuchElementException; |
|
39 import java.util.StringTokenizer; |
|
40 import java.util.jar.Manifest; |
|
41 import java.util.jar.Attributes; |
|
42 import java.util.jar.Attributes.Name; |
|
43 import java.security.CodeSigner; |
|
44 import java.security.PrivilegedAction; |
|
45 import java.security.PrivilegedExceptionAction; |
|
46 import java.security.AccessController; |
|
47 import java.security.AccessControlContext; |
|
48 import java.security.SecureClassLoader; |
|
49 import java.security.CodeSource; |
|
50 import java.security.Permission; |
|
51 import java.security.PermissionCollection; |
|
52 import sun.misc.Resource; |
|
53 import sun.misc.URLClassPath; |
|
54 import sun.net.www.ParseUtil; |
|
55 import sun.security.util.SecurityConstants; |
|
56 |
|
57 /** |
|
58 * This class loader is used to load classes and resources from a search |
|
59 * path of URLs referring to both JAR files and directories. Any URL that |
|
60 * ends with a '/' is assumed to refer to a directory. Otherwise, the URL |
|
61 * is assumed to refer to a JAR file which will be opened as needed. |
|
62 * <p> |
|
63 * The AccessControlContext of the thread that created the instance of |
|
64 * URLClassLoader will be used when subsequently loading classes and |
|
65 * resources. |
|
66 * <p> |
|
67 * The classes that are loaded are by default granted permission only to |
|
68 * access the URLs specified when the URLClassLoader was created. |
|
69 * |
|
70 * @author David Connelly |
|
71 * @since 1.2 |
|
72 */ |
|
73 public class URLClassLoader extends SecureClassLoader { |
|
74 /* The search path for classes and resources */ |
|
75 URLClassPath ucp; |
|
76 |
|
77 /* The context to be used when loading classes and resources */ |
|
78 private AccessControlContext acc; |
|
79 |
|
80 /** |
|
81 * Constructs a new URLClassLoader for the given URLs. The URLs will be |
|
82 * searched in the order specified for classes and resources after first |
|
83 * searching in the specified parent class loader. Any URL that ends with |
|
84 * a '/' is assumed to refer to a directory. Otherwise, the URL is assumed |
|
85 * to refer to a JAR file which will be downloaded and opened as needed. |
|
86 * |
|
87 * <p>If there is a security manager, this method first |
|
88 * calls the security manager's <code>checkCreateClassLoader</code> method |
|
89 * to ensure creation of a class loader is allowed. |
|
90 * |
|
91 * @param urls the URLs from which to load classes and resources |
|
92 * @param parent the parent class loader for delegation |
|
93 * @exception SecurityException if a security manager exists and its |
|
94 * <code>checkCreateClassLoader</code> method doesn't allow |
|
95 * creation of a class loader. |
|
96 * @see SecurityManager#checkCreateClassLoader |
|
97 */ |
|
98 public URLClassLoader(URL[] urls, ClassLoader parent) { |
|
99 super(parent); |
|
100 // this is to make the stack depth consistent with 1.1 |
|
101 SecurityManager security = System.getSecurityManager(); |
|
102 if (security != null) { |
|
103 security.checkCreateClassLoader(); |
|
104 } |
|
105 ucp = new URLClassPath(urls); |
|
106 acc = AccessController.getContext(); |
|
107 } |
|
108 |
|
109 /** |
|
110 * Constructs a new URLClassLoader for the specified URLs using the |
|
111 * default delegation parent <code>ClassLoader</code>. The URLs will |
|
112 * be searched in the order specified for classes and resources after |
|
113 * first searching in the parent class loader. Any URL that ends with |
|
114 * a '/' is assumed to refer to a directory. Otherwise, the URL is |
|
115 * assumed to refer to a JAR file which will be downloaded and opened |
|
116 * as needed. |
|
117 * |
|
118 * <p>If there is a security manager, this method first |
|
119 * calls the security manager's <code>checkCreateClassLoader</code> method |
|
120 * to ensure creation of a class loader is allowed. |
|
121 * |
|
122 * @param urls the URLs from which to load classes and resources |
|
123 * |
|
124 * @exception SecurityException if a security manager exists and its |
|
125 * <code>checkCreateClassLoader</code> method doesn't allow |
|
126 * creation of a class loader. |
|
127 * @see SecurityManager#checkCreateClassLoader |
|
128 */ |
|
129 public URLClassLoader(URL[] urls) { |
|
130 super(); |
|
131 // this is to make the stack depth consistent with 1.1 |
|
132 SecurityManager security = System.getSecurityManager(); |
|
133 if (security != null) { |
|
134 security.checkCreateClassLoader(); |
|
135 } |
|
136 ucp = new URLClassPath(urls); |
|
137 acc = AccessController.getContext(); |
|
138 } |
|
139 |
|
140 /** |
|
141 * Constructs a new URLClassLoader for the specified URLs, parent |
|
142 * class loader, and URLStreamHandlerFactory. The parent argument |
|
143 * will be used as the parent class loader for delegation. The |
|
144 * factory argument will be used as the stream handler factory to |
|
145 * obtain protocol handlers when creating new jar URLs. |
|
146 * |
|
147 * <p>If there is a security manager, this method first |
|
148 * calls the security manager's <code>checkCreateClassLoader</code> method |
|
149 * to ensure creation of a class loader is allowed. |
|
150 * |
|
151 * @param urls the URLs from which to load classes and resources |
|
152 * @param parent the parent class loader for delegation |
|
153 * @param factory the URLStreamHandlerFactory to use when creating URLs |
|
154 * |
|
155 * @exception SecurityException if a security manager exists and its |
|
156 * <code>checkCreateClassLoader</code> method doesn't allow |
|
157 * creation of a class loader. |
|
158 * @see SecurityManager#checkCreateClassLoader |
|
159 */ |
|
160 public URLClassLoader(URL[] urls, ClassLoader parent, |
|
161 URLStreamHandlerFactory factory) { |
|
162 super(parent); |
|
163 // this is to make the stack depth consistent with 1.1 |
|
164 SecurityManager security = System.getSecurityManager(); |
|
165 if (security != null) { |
|
166 security.checkCreateClassLoader(); |
|
167 } |
|
168 ucp = new URLClassPath(urls, factory); |
|
169 acc = AccessController.getContext(); |
|
170 } |
|
171 |
|
172 /** |
|
173 * Appends the specified URL to the list of URLs to search for |
|
174 * classes and resources. |
|
175 * <p> |
|
176 * If the URL specified is <code>null</code> or is already in the |
|
177 * list of URLs, then invoking this method has no effect. |
|
178 * |
|
179 * @param url the URL to be added to the search path of URLs |
|
180 */ |
|
181 protected void addURL(URL url) { |
|
182 ucp.addURL(url); |
|
183 } |
|
184 |
|
185 /** |
|
186 * Returns the search path of URLs for loading classes and resources. |
|
187 * This includes the original list of URLs specified to the constructor, |
|
188 * along with any URLs subsequently appended by the addURL() method. |
|
189 * @return the search path of URLs for loading classes and resources. |
|
190 */ |
|
191 public URL[] getURLs() { |
|
192 return ucp.getURLs(); |
|
193 } |
|
194 |
|
195 /** |
|
196 * Finds and loads the class with the specified name from the URL search |
|
197 * path. Any URLs referring to JAR files are loaded and opened as needed |
|
198 * until the class is found. |
|
199 * |
|
200 * @param name the name of the class |
|
201 * @return the resulting class |
|
202 * @exception ClassNotFoundException if the class could not be found |
|
203 */ |
|
204 protected Class<?> findClass(final String name) |
|
205 throws ClassNotFoundException |
|
206 { |
|
207 try { |
|
208 return (Class) |
|
209 AccessController.doPrivileged(new PrivilegedExceptionAction() { |
|
210 public Object run() throws ClassNotFoundException { |
|
211 String path = name.replace('.', '/').concat(".class"); |
|
212 Resource res = ucp.getResource(path, false); |
|
213 if (res != null) { |
|
214 try { |
|
215 return defineClass(name, res); |
|
216 } catch (IOException e) { |
|
217 throw new ClassNotFoundException(name, e); |
|
218 } |
|
219 } else { |
|
220 throw new ClassNotFoundException(name); |
|
221 } |
|
222 } |
|
223 }, acc); |
|
224 } catch (java.security.PrivilegedActionException pae) { |
|
225 throw (ClassNotFoundException) pae.getException(); |
|
226 } |
|
227 } |
|
228 |
|
229 /* |
|
230 * Defines a Class using the class bytes obtained from the specified |
|
231 * Resource. The resulting Class must be resolved before it can be |
|
232 * used. |
|
233 */ |
|
234 private Class defineClass(String name, Resource res) throws IOException { |
|
235 int i = name.lastIndexOf('.'); |
|
236 URL url = res.getCodeSourceURL(); |
|
237 if (i != -1) { |
|
238 String pkgname = name.substring(0, i); |
|
239 // Check if package already loaded. |
|
240 Package pkg = getPackage(pkgname); |
|
241 Manifest man = res.getManifest(); |
|
242 if (pkg != null) { |
|
243 // Package found, so check package sealing. |
|
244 if (pkg.isSealed()) { |
|
245 // Verify that code source URL is the same. |
|
246 if (!pkg.isSealed(url)) { |
|
247 throw new SecurityException( |
|
248 "sealing violation: package " + pkgname + " is sealed"); |
|
249 } |
|
250 |
|
251 } else { |
|
252 // Make sure we are not attempting to seal the package |
|
253 // at this code source URL. |
|
254 if ((man != null) && isSealed(pkgname, man)) { |
|
255 throw new SecurityException( |
|
256 "sealing violation: can't seal package " + pkgname + |
|
257 ": already loaded"); |
|
258 } |
|
259 } |
|
260 } else { |
|
261 if (man != null) { |
|
262 definePackage(pkgname, man, url); |
|
263 } else { |
|
264 definePackage(pkgname, null, null, null, null, null, null, null); |
|
265 } |
|
266 } |
|
267 } |
|
268 // Now read the class bytes and define the class |
|
269 java.nio.ByteBuffer bb = res.getByteBuffer(); |
|
270 if (bb != null) { |
|
271 // Use (direct) ByteBuffer: |
|
272 CodeSigner[] signers = res.getCodeSigners(); |
|
273 CodeSource cs = new CodeSource(url, signers); |
|
274 return defineClass(name, bb, cs); |
|
275 } else { |
|
276 byte[] b = res.getBytes(); |
|
277 // must read certificates AFTER reading bytes. |
|
278 CodeSigner[] signers = res.getCodeSigners(); |
|
279 CodeSource cs = new CodeSource(url, signers); |
|
280 return defineClass(name, b, 0, b.length, cs); |
|
281 } |
|
282 } |
|
283 |
|
284 /** |
|
285 * Defines a new package by name in this ClassLoader. The attributes |
|
286 * contained in the specified Manifest will be used to obtain package |
|
287 * version and sealing information. For sealed packages, the additional |
|
288 * URL specifies the code source URL from which the package was loaded. |
|
289 * |
|
290 * @param name the package name |
|
291 * @param man the Manifest containing package version and sealing |
|
292 * information |
|
293 * @param url the code source url for the package, or null if none |
|
294 * @exception IllegalArgumentException if the package name duplicates |
|
295 * an existing package either in this class loader or one |
|
296 * of its ancestors |
|
297 * @return the newly defined Package object |
|
298 */ |
|
299 protected Package definePackage(String name, Manifest man, URL url) |
|
300 throws IllegalArgumentException |
|
301 { |
|
302 String path = name.replace('.', '/').concat("/"); |
|
303 String specTitle = null, specVersion = null, specVendor = null; |
|
304 String implTitle = null, implVersion = null, implVendor = null; |
|
305 String sealed = null; |
|
306 URL sealBase = null; |
|
307 |
|
308 Attributes attr = man.getAttributes(path); |
|
309 if (attr != null) { |
|
310 specTitle = attr.getValue(Name.SPECIFICATION_TITLE); |
|
311 specVersion = attr.getValue(Name.SPECIFICATION_VERSION); |
|
312 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); |
|
313 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); |
|
314 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); |
|
315 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); |
|
316 sealed = attr.getValue(Name.SEALED); |
|
317 } |
|
318 attr = man.getMainAttributes(); |
|
319 if (attr != null) { |
|
320 if (specTitle == null) { |
|
321 specTitle = attr.getValue(Name.SPECIFICATION_TITLE); |
|
322 } |
|
323 if (specVersion == null) { |
|
324 specVersion = attr.getValue(Name.SPECIFICATION_VERSION); |
|
325 } |
|
326 if (specVendor == null) { |
|
327 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); |
|
328 } |
|
329 if (implTitle == null) { |
|
330 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); |
|
331 } |
|
332 if (implVersion == null) { |
|
333 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); |
|
334 } |
|
335 if (implVendor == null) { |
|
336 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); |
|
337 } |
|
338 if (sealed == null) { |
|
339 sealed = attr.getValue(Name.SEALED); |
|
340 } |
|
341 } |
|
342 if ("true".equalsIgnoreCase(sealed)) { |
|
343 sealBase = url; |
|
344 } |
|
345 return definePackage(name, specTitle, specVersion, specVendor, |
|
346 implTitle, implVersion, implVendor, sealBase); |
|
347 } |
|
348 |
|
349 /* |
|
350 * Returns true if the specified package name is sealed according to the |
|
351 * given manifest. |
|
352 */ |
|
353 private boolean isSealed(String name, Manifest man) { |
|
354 String path = name.replace('.', '/').concat("/"); |
|
355 Attributes attr = man.getAttributes(path); |
|
356 String sealed = null; |
|
357 if (attr != null) { |
|
358 sealed = attr.getValue(Name.SEALED); |
|
359 } |
|
360 if (sealed == null) { |
|
361 if ((attr = man.getMainAttributes()) != null) { |
|
362 sealed = attr.getValue(Name.SEALED); |
|
363 } |
|
364 } |
|
365 return "true".equalsIgnoreCase(sealed); |
|
366 } |
|
367 |
|
368 /** |
|
369 * Finds the resource with the specified name on the URL search path. |
|
370 * |
|
371 * @param name the name of the resource |
|
372 * @return a <code>URL</code> for the resource, or <code>null</code> |
|
373 * if the resource could not be found. |
|
374 */ |
|
375 public URL findResource(final String name) { |
|
376 /* |
|
377 * The same restriction to finding classes applies to resources |
|
378 */ |
|
379 URL url = |
|
380 (URL) AccessController.doPrivileged(new PrivilegedAction() { |
|
381 public Object run() { |
|
382 return ucp.findResource(name, true); |
|
383 } |
|
384 }, acc); |
|
385 |
|
386 return url != null ? ucp.checkURL(url) : null; |
|
387 } |
|
388 |
|
389 /** |
|
390 * Returns an Enumeration of URLs representing all of the resources |
|
391 * on the URL search path having the specified name. |
|
392 * |
|
393 * @param name the resource name |
|
394 * @exception IOException if an I/O exception occurs |
|
395 * @return an <code>Enumeration</code> of <code>URL</code>s |
|
396 */ |
|
397 public Enumeration<URL> findResources(final String name) |
|
398 throws IOException |
|
399 { |
|
400 final Enumeration e = ucp.findResources(name, true); |
|
401 |
|
402 return new Enumeration<URL>() { |
|
403 private URL url = null; |
|
404 |
|
405 private boolean next() { |
|
406 if (url != null) { |
|
407 return true; |
|
408 } |
|
409 do { |
|
410 URL u = (URL) |
|
411 AccessController.doPrivileged(new PrivilegedAction() { |
|
412 public Object run() { |
|
413 if (!e.hasMoreElements()) |
|
414 return null; |
|
415 return e.nextElement(); |
|
416 } |
|
417 }, acc); |
|
418 if (u == null) |
|
419 break; |
|
420 url = ucp.checkURL(u); |
|
421 } while (url == null); |
|
422 return url != null; |
|
423 } |
|
424 |
|
425 public URL nextElement() { |
|
426 if (!next()) { |
|
427 throw new NoSuchElementException(); |
|
428 } |
|
429 URL u = url; |
|
430 url = null; |
|
431 return u; |
|
432 } |
|
433 |
|
434 public boolean hasMoreElements() { |
|
435 return next(); |
|
436 } |
|
437 }; |
|
438 } |
|
439 |
|
440 /** |
|
441 * Returns the permissions for the given codesource object. |
|
442 * The implementation of this method first calls super.getPermissions |
|
443 * and then adds permissions based on the URL of the codesource. |
|
444 * <p> |
|
445 * If the protocol of this URL is "jar", then the permission granted |
|
446 * is based on the permission that is required by the URL of the Jar |
|
447 * file. |
|
448 * <p> |
|
449 * If the protocol is "file" and there is an authority component, then |
|
450 * permission to connect to and accept connections from that authority |
|
451 * may be granted. If the protocol is "file" |
|
452 * and the path specifies a file, then permission to read that |
|
453 * file is granted. If protocol is "file" and the path is |
|
454 * a directory, permission is granted to read all files |
|
455 * and (recursively) all files and subdirectories contained in |
|
456 * that directory. |
|
457 * <p> |
|
458 * If the protocol is not "file", then permission |
|
459 * to connect to and accept connections from the URL's host is granted. |
|
460 * @param codesource the codesource |
|
461 * @return the permissions granted to the codesource |
|
462 */ |
|
463 protected PermissionCollection getPermissions(CodeSource codesource) |
|
464 { |
|
465 PermissionCollection perms = super.getPermissions(codesource); |
|
466 |
|
467 URL url = codesource.getLocation(); |
|
468 |
|
469 Permission p; |
|
470 URLConnection urlConnection; |
|
471 |
|
472 try { |
|
473 urlConnection = url.openConnection(); |
|
474 p = urlConnection.getPermission(); |
|
475 } catch (java.io.IOException ioe) { |
|
476 p = null; |
|
477 urlConnection = null; |
|
478 } |
|
479 |
|
480 if (p instanceof FilePermission) { |
|
481 // if the permission has a separator char on the end, |
|
482 // it means the codebase is a directory, and we need |
|
483 // to add an additional permission to read recursively |
|
484 String path = p.getName(); |
|
485 if (path.endsWith(File.separator)) { |
|
486 path += "-"; |
|
487 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION); |
|
488 } |
|
489 } else if ((p == null) && (url.getProtocol().equals("file"))) { |
|
490 String path = url.getFile().replace('/', File.separatorChar); |
|
491 path = ParseUtil.decode(path); |
|
492 if (path.endsWith(File.separator)) |
|
493 path += "-"; |
|
494 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION); |
|
495 } else { |
|
496 /** |
|
497 * Not loading from a 'file:' URL so we want to give the class |
|
498 * permission to connect to and accept from the remote host |
|
499 * after we've made sure the host is the correct one and is valid. |
|
500 */ |
|
501 URL locUrl = url; |
|
502 if (urlConnection instanceof JarURLConnection) { |
|
503 locUrl = ((JarURLConnection)urlConnection).getJarFileURL(); |
|
504 } |
|
505 String host = locUrl.getHost(); |
|
506 if (host != null && (host.length() > 0)) |
|
507 p = new SocketPermission(host, |
|
508 SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION); |
|
509 } |
|
510 |
|
511 // make sure the person that created this class loader |
|
512 // would have this permission |
|
513 |
|
514 if (p != null) { |
|
515 final SecurityManager sm = System.getSecurityManager(); |
|
516 if (sm != null) { |
|
517 final Permission fp = p; |
|
518 AccessController.doPrivileged(new PrivilegedAction() { |
|
519 public Object run() throws SecurityException { |
|
520 sm.checkPermission(fp); |
|
521 return null; |
|
522 } |
|
523 }, acc); |
|
524 } |
|
525 perms.add(p); |
|
526 } |
|
527 return perms; |
|
528 } |
|
529 |
|
530 /** |
|
531 * Creates a new instance of URLClassLoader for the specified |
|
532 * URLs and parent class loader. If a security manager is |
|
533 * installed, the <code>loadClass</code> method of the URLClassLoader |
|
534 * returned by this method will invoke the |
|
535 * <code>SecurityManager.checkPackageAccess</code> method before |
|
536 * loading the class. |
|
537 * |
|
538 * @param urls the URLs to search for classes and resources |
|
539 * @param parent the parent class loader for delegation |
|
540 * @return the resulting class loader |
|
541 */ |
|
542 public static URLClassLoader newInstance(final URL[] urls, |
|
543 final ClassLoader parent) { |
|
544 // Save the caller's context |
|
545 AccessControlContext acc = AccessController.getContext(); |
|
546 // Need a privileged block to create the class loader |
|
547 URLClassLoader ucl = |
|
548 (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction() { |
|
549 public Object run() { |
|
550 return new FactoryURLClassLoader(urls, parent); |
|
551 } |
|
552 }); |
|
553 // Now set the context on the loader using the one we saved, |
|
554 // not the one inside the privileged block... |
|
555 ucl.acc = acc; |
|
556 return ucl; |
|
557 } |
|
558 |
|
559 /** |
|
560 * Creates a new instance of URLClassLoader for the specified |
|
561 * URLs and default parent class loader. If a security manager is |
|
562 * installed, the <code>loadClass</code> method of the URLClassLoader |
|
563 * returned by this method will invoke the |
|
564 * <code>SecurityManager.checkPackageAccess</code> before |
|
565 * loading the class. |
|
566 * |
|
567 * @param urls the URLs to search for classes and resources |
|
568 * @return the resulting class loader |
|
569 */ |
|
570 public static URLClassLoader newInstance(final URL[] urls) { |
|
571 // Save the caller's context |
|
572 AccessControlContext acc = AccessController.getContext(); |
|
573 // Need a privileged block to create the class loader |
|
574 URLClassLoader ucl = (URLClassLoader) |
|
575 AccessController.doPrivileged(new PrivilegedAction() { |
|
576 public Object run() { |
|
577 return new FactoryURLClassLoader(urls); |
|
578 } |
|
579 }); |
|
580 |
|
581 // Now set the context on the loader using the one we saved, |
|
582 // not the one inside the privileged block... |
|
583 ucl.acc = acc; |
|
584 return ucl; |
|
585 } |
|
586 |
|
587 static { |
|
588 sun.misc.SharedSecrets.setJavaNetAccess ( |
|
589 new sun.misc.JavaNetAccess() { |
|
590 public URLClassPath getURLClassPath (URLClassLoader u) { |
|
591 return u.ucp; |
|
592 } |
|
593 } |
|
594 ); |
|
595 } |
|
596 } |
|
597 |
|
598 final class FactoryURLClassLoader extends URLClassLoader { |
|
599 |
|
600 FactoryURLClassLoader(URL[] urls, ClassLoader parent) { |
|
601 super(urls, parent); |
|
602 } |
|
603 |
|
604 FactoryURLClassLoader(URL[] urls) { |
|
605 super(urls); |
|
606 } |
|
607 |
|
608 public final synchronized Class loadClass(String name, boolean resolve) |
|
609 throws ClassNotFoundException |
|
610 { |
|
611 // First check if we have permission to access the package. This |
|
612 // should go away once we've added support for exported packages. |
|
613 SecurityManager sm = System.getSecurityManager(); |
|
614 if (sm != null) { |
|
615 int i = name.lastIndexOf('.'); |
|
616 if (i != -1) { |
|
617 sm.checkPackageAccess(name.substring(0, i)); |
|
618 } |
|
619 } |
|
620 return super.loadClass(name, resolve); |
|
621 } |
|
622 } |