95
96 /** table of class loaders that use codebase property for annotation */
97 private static final Map<ClassLoader, Void> codebaseLoaders =
98 Collections.synchronizedMap(new IdentityHashMap<ClassLoader, Void>(5));
99 static {
100 for (ClassLoader codebaseLoader = ClassLoader.getSystemClassLoader();
101 codebaseLoader != null;
102 codebaseLoader = codebaseLoader.getParent())
103 {
104 codebaseLoaders.put(codebaseLoader, null);
105 }
106 }
107
108 /**
109 * table mapping codebase URL path and context class loader pairs
110 * to class loader instances. Entries hold class loaders with weak
111 * references, so this table does not prevent loaders from being
112 * garbage collected.
113 */
114 private static final HashMap<LoaderKey, LoaderEntry> loaderTable
115 = new HashMap<LoaderKey, LoaderEntry>(5);
116
117 /** reference queue for cleared class loader entries */
118 private static final ReferenceQueue<Loader> refQueue
119 = new ReferenceQueue<Loader>();
120
121 /*
122 * Disallow anyone from creating one of these.
123 */
124 private LoaderHandler() {}
125
126 /**
127 * Returns an array of URLs initialized with the value of the
128 * java.rmi.server.codebase property as the URL path.
129 */
130 private static synchronized URL[] getDefaultCodebaseURLs()
131 throws MalformedURLException
132 {
133 /*
134 * If it hasn't already been done, convert the codebase property
135 * into an array of URLs; this may throw a MalformedURLException.
136 */
137 if (codebaseURLs == null) {
138 if (codebaseProperty != null) {
139 codebaseURLs = pathToURLs(codebaseProperty);
140 } else {
141 codebaseURLs = new URL[0];
142 }
143 }
144 return codebaseURLs;
145 }
146
147 /**
148 * Load a class from a network location (one or more URLs),
149 * but first try to resolve the named class through the given
150 * "default loader".
151 */
152 public static Class loadClass(String codebase, String name,
153 ClassLoader defaultLoader)
154 throws MalformedURLException, ClassNotFoundException
155 {
156 if (loaderLog.isLoggable(Log.BRIEF)) {
157 loaderLog.log(Log.BRIEF,
158 "name = \"" + name + "\", " +
159 "codebase = \"" + (codebase != null ? codebase : "") + "\"" +
160 (defaultLoader != null ?
161 ", defaultLoader = " + defaultLoader : ""));
162 }
163
164 URL[] urls;
165 if (codebase != null) {
166 urls = pathToURLs(codebase);
167 } else {
168 urls = getDefaultCodebaseURLs();
169 }
170
171 if (defaultLoader != null) {
172 try {
173 Class c = Class.forName(name, false, defaultLoader);
174 if (loaderLog.isLoggable(Log.VERBOSE)) {
175 loaderLog.log(Log.VERBOSE,
176 "class \"" + name + "\" found via defaultLoader, " +
177 "defined by " + c.getClassLoader());
178 }
179 return c;
180 } catch (ClassNotFoundException e) {
181 }
182 }
183
184 return loadClass(urls, name);
185 }
186
187 /**
188 * Returns the class annotation (representing the location for
189 * a class) that RMI will use to annotate the call stream when
190 * marshalling objects of the given class.
191 */
192 public static String getClassAnnotation(Class cl) {
193 String name = cl.getName();
194
195 /*
196 * Class objects for arrays of primitive types never need an
197 * annotation, because they never need to be (or can be) downloaded.
198 *
199 * REMIND: should we (not) be annotating classes that are in
200 * "java.*" packages?
201 */
202 int nameLength = name.length();
203 if (nameLength > 0 && name.charAt(0) == '[') {
204 // skip past all '[' characters (see bugid 4211906)
205 int i = 1;
206 while (nameLength > i && name.charAt(i) == '[') {
207 i++;
208 }
209 if (nameLength > i && name.charAt(i) != 'L') {
210 return null;
211 }
212 }
244 * we must verify that the current access control context
245 * has permission to know all of these URLs.
246 */
247 SecurityManager sm = System.getSecurityManager();
248 if (sm != null) {
249 Permissions perms = new Permissions();
250 for (int i = 0; i < urls.length; i++) {
251 Permission p =
252 urls[i].openConnection().getPermission();
253 if (p != null) {
254 if (!perms.implies(p)) {
255 sm.checkPermission(p);
256 perms.add(p);
257 }
258 }
259 }
260 }
261
262 annotation = urlsToPath(urls);
263 }
264 } catch (SecurityException e) {
265 /*
266 * If access was denied to the knowledge of the class
267 * loader's URLs, fall back to the default behavior.
268 */
269 } catch (IOException e) {
270 /*
271 * This shouldn't happen, although it is declared to be
272 * thrown by openConnection() and getPermission(). If it
273 * does happen, forget about this class loader's URLs and
274 * fall back to the default behavior.
275 */
276 }
277 }
278
279 if (annotation != null) {
280 return annotation;
281 } else {
282 return codebaseProperty; // REMIND: does this make sense??
283 }
284 }
285
286 /**
287 * Returns a classloader that loads classes from the given codebase URL
288 * path. The parent classloader of the returned classloader is the
289 * context class loader.
290 */
291 public static ClassLoader getClassLoader(String codebase)
292 throws MalformedURLException
341 URL[] urls = ((Loader) loader).getURLs();
342 if (urls.length > 0) {
343 return urls[0];
344 }
345 }
346 return null;
347 }
348
349 /**
350 * Register a class loader as one whose classes should always be
351 * annotated with the value of the "java.rmi.server.codebase" property.
352 */
353 public static void registerCodebaseLoader(ClassLoader loader) {
354 codebaseLoaders.put(loader, null);
355 }
356
357 /**
358 * Load a class from the RMI class loader corresponding to the given
359 * codebase URL path in the current execution context.
360 */
361 private static Class loadClass(URL[] urls, String name)
362 throws ClassNotFoundException
363 {
364 ClassLoader parent = getRMIContextClassLoader();
365 if (loaderLog.isLoggable(Log.VERBOSE)) {
366 loaderLog.log(Log.VERBOSE,
367 "(thread context class loader: " + parent + ")");
368 }
369
370 /*
371 * If no security manager is set, disable access to RMI class
372 * loaders and simply delegate request to the parent loader
373 * (see bugid 4140511).
374 */
375 SecurityManager sm = System.getSecurityManager();
376 if (sm == null) {
377 try {
378 Class c = Class.forName(name, false, parent);
379 if (loaderLog.isLoggable(Log.VERBOSE)) {
380 loaderLog.log(Log.VERBOSE,
381 "class \"" + name + "\" found via " +
382 "thread context class loader " +
383 "(no security manager: codebase disabled), " +
384 "defined by " + c.getClassLoader());
385 }
386 return c;
387 } catch (ClassNotFoundException e) {
388 if (loaderLog.isLoggable(Log.BRIEF)) {
389 loaderLog.log(Log.BRIEF,
390 "class \"" + name + "\" not found via " +
391 "thread context class loader " +
392 "(no security manager: codebase disabled)", e);
393 }
394 throw new ClassNotFoundException(e.getMessage() +
395 " (no security manager: RMI class loader disabled)",
396 e.getException());
397 }
398 }
407 if (loader != null) {
408 /*
409 * Verify that the caller has permission to access this loader.
410 */
411 loader.checkPermissions();
412 }
413 } catch (SecurityException e) {
414 /*
415 * If the current access control context does not have permission
416 * to access all of the URLs in the codebase path, wrap the
417 * resulting security exception in a ClassNotFoundException, so
418 * the caller can handle this outcome just like any other class
419 * loading failure (see bugid 4146529).
420 */
421 try {
422 /*
423 * But first, check to see if the named class could have been
424 * resolved without the security-offending codebase anyway;
425 * if so, return successfully (see bugids 4191926 & 4349670).
426 */
427 Class c = Class.forName(name, false, parent);
428 if (loaderLog.isLoggable(Log.VERBOSE)) {
429 loaderLog.log(Log.VERBOSE,
430 "class \"" + name + "\" found via " +
431 "thread context class loader " +
432 "(access to codebase denied), " +
433 "defined by " + c.getClassLoader());
434 }
435 return c;
436 } catch (ClassNotFoundException unimportant) {
437 /*
438 * Presumably the security exception is the more important
439 * exception to report in this case.
440 */
441 if (loaderLog.isLoggable(Log.BRIEF)) {
442 loaderLog.log(Log.BRIEF,
443 "class \"" + name + "\" not found via " +
444 "thread context class loader " +
445 "(access to codebase denied)", e);
446 }
447 throw new ClassNotFoundException(
448 "access to class loader denied", e);
449 }
450 }
451
452 try {
453 Class c = Class.forName(name, false, loader);
454 if (loaderLog.isLoggable(Log.VERBOSE)) {
455 loaderLog.log(Log.VERBOSE,
456 "class \"" + name + "\" " + "found via codebase, " +
457 "defined by " + c.getClassLoader());
458 }
459 return c;
460 } catch (ClassNotFoundException e) {
461 if (loaderLog.isLoggable(Log.BRIEF)) {
462 loaderLog.log(Log.BRIEF,
463 "class \"" + name + "\" not found via codebase", e);
464 }
465 throw e;
466 }
467 }
468
469 /**
470 * Define and return a dynamic proxy class in a class loader with
471 * URLs supplied in the given location. The proxy class will
472 * implement interface classes named by the given array of
473 * interface names.
474 */
475 public static Class loadProxyClass(String codebase, String[] interfaces,
476 ClassLoader defaultLoader)
477 throws MalformedURLException, ClassNotFoundException
478 {
479 if (loaderLog.isLoggable(Log.BRIEF)) {
480 loaderLog.log(Log.BRIEF,
481 "interfaces = " + Arrays.asList(interfaces) + ", " +
482 "codebase = \"" + (codebase != null ? codebase : "") + "\"" +
483 (defaultLoader != null ?
484 ", defaultLoader = " + defaultLoader : ""));
485 }
486
487 /*
488 * This method uses a fairly complex algorithm to load the
489 * proxy class and its interface classes in order to maximize
490 * the likelihood that the proxy's codebase annotation will be
491 * preserved. The algorithm is (assuming that all of the
492 * proxy interface classes are public):
493 *
494 * If the default loader is not null, try to load the proxy
495 * interfaces through that loader. If the interfaces can be
520 ClassLoader parent = getRMIContextClassLoader();
521 if (loaderLog.isLoggable(Log.VERBOSE)) {
522 loaderLog.log(Log.VERBOSE,
523 "(thread context class loader: " + parent + ")");
524 }
525
526 URL[] urls;
527 if (codebase != null) {
528 urls = pathToURLs(codebase);
529 } else {
530 urls = getDefaultCodebaseURLs();
531 }
532
533 /*
534 * If no security manager is set, disable access to RMI class
535 * loaders and use the would-de parent instead.
536 */
537 SecurityManager sm = System.getSecurityManager();
538 if (sm == null) {
539 try {
540 Class c = loadProxyClass(interfaces, defaultLoader, parent,
541 false);
542 if (loaderLog.isLoggable(Log.VERBOSE)) {
543 loaderLog.log(Log.VERBOSE,
544 "(no security manager: codebase disabled) " +
545 "proxy class defined by " + c.getClassLoader());
546 }
547 return c;
548 } catch (ClassNotFoundException e) {
549 if (loaderLog.isLoggable(Log.BRIEF)) {
550 loaderLog.log(Log.BRIEF,
551 "(no security manager: codebase disabled) " +
552 "proxy class resolution failed", e);
553 }
554 throw new ClassNotFoundException(e.getMessage() +
555 " (no security manager: RMI class loader disabled)",
556 e.getException());
557 }
558 }
559
560 /*
567 if (loader != null) {
568 /*
569 * Verify that the caller has permission to access this loader.
570 */
571 loader.checkPermissions();
572 }
573 } catch (SecurityException e) {
574 /*
575 * If the current access control context does not have permission
576 * to access all of the URLs in the codebase path, wrap the
577 * resulting security exception in a ClassNotFoundException, so
578 * the caller can handle this outcome just like any other class
579 * loading failure (see bugid 4146529).
580 */
581 try {
582 /*
583 * But first, check to see if the proxy class could have been
584 * resolved without the security-offending codebase anyway;
585 * if so, return successfully (see bugids 4191926 & 4349670).
586 */
587 Class c = loadProxyClass(interfaces, defaultLoader, parent,
588 false);
589 if (loaderLog.isLoggable(Log.VERBOSE)) {
590 loaderLog.log(Log.VERBOSE,
591 "(access to codebase denied) " +
592 "proxy class defined by " + c.getClassLoader());
593 }
594 return c;
595 } catch (ClassNotFoundException unimportant) {
596 /*
597 * Presumably the security exception is the more important
598 * exception to report in this case.
599 */
600 if (loaderLog.isLoggable(Log.BRIEF)) {
601 loaderLog.log(Log.BRIEF,
602 "(access to codebase denied) " +
603 "proxy class resolution failed", e);
604 }
605 throw new ClassNotFoundException(
606 "access to class loader denied", e);
607 }
608 }
609
610 try {
611 Class c = loadProxyClass(interfaces, defaultLoader, loader, true);
612 if (loaderLog.isLoggable(Log.VERBOSE)) {
613 loaderLog.log(Log.VERBOSE,
614 "proxy class defined by " + c.getClassLoader());
615 }
616 return c;
617 } catch (ClassNotFoundException e) {
618 if (loaderLog.isLoggable(Log.BRIEF)) {
619 loaderLog.log(Log.BRIEF,
620 "proxy class resolution failed", e);
621 }
622 throw e;
623 }
624 }
625
626 /**
627 * Define a proxy class in the default loader if appropriate.
628 * Define the class in an RMI class loader otherwise. The proxy
629 * class will implement classes which are named in the supplied
630 * interfaceNames.
631 */
632 private static Class loadProxyClass(String[] interfaceNames,
633 ClassLoader defaultLoader,
634 ClassLoader codebaseLoader,
635 boolean preferCodebase)
636 throws ClassNotFoundException
637 {
638 ClassLoader proxyLoader = null;
639 Class[] classObjs = new Class[interfaceNames.length];
640 boolean[] nonpublic = { false };
641
642 defaultLoaderCase:
643 if (defaultLoader != null) {
644 try {
645 proxyLoader =
646 loadProxyInterfaces(interfaceNames, defaultLoader,
647 classObjs, nonpublic);
648 if (loaderLog.isLoggable(Log.VERBOSE)) {
649 ClassLoader[] definingLoaders =
650 new ClassLoader[classObjs.length];
651 for (int i = 0; i < definingLoaders.length; i++) {
652 definingLoaders[i] = classObjs[i].getClassLoader();
653 }
654 loaderLog.log(Log.VERBOSE,
655 "proxy interfaces found via defaultLoader, " +
656 "defined by " + Arrays.asList(definingLoaders));
657 }
658 } catch (ClassNotFoundException e) {
659 break defaultLoaderCase;
675 classObjs, nonpublic);
676 if (loaderLog.isLoggable(Log.VERBOSE)) {
677 ClassLoader[] definingLoaders = new ClassLoader[classObjs.length];
678 for (int i = 0; i < definingLoaders.length; i++) {
679 definingLoaders[i] = classObjs[i].getClassLoader();
680 }
681 loaderLog.log(Log.VERBOSE,
682 "proxy interfaces found via codebase, " +
683 "defined by " + Arrays.asList(definingLoaders));
684 }
685 if (!nonpublic[0]) {
686 proxyLoader = codebaseLoader;
687 }
688 return loadProxyClass(proxyLoader, classObjs);
689 }
690
691 /**
692 * Define a proxy class in the given class loader. The proxy
693 * class will implement the given interfaces Classes.
694 */
695 private static Class loadProxyClass(ClassLoader loader, Class[] interfaces)
696 throws ClassNotFoundException
697 {
698 try {
699 return Proxy.getProxyClass(loader, interfaces);
700 } catch (IllegalArgumentException e) {
701 throw new ClassNotFoundException(
702 "error creating dynamic proxy class", e);
703 }
704 }
705
706 /*
707 * Load Class objects for the names in the interfaces array fron
708 * the given class loader.
709 *
710 * We pass classObjs and nonpublic arrays to avoid needing a
711 * multi-element return value. nonpublic is an array to enable
712 * the method to take a boolean argument by reference.
713 *
714 * nonpublic array is needed to signal when the return value of
715 * this method should be used as the proxy class loader. Because
716 * null represents a valid class loader, that value is
717 * insufficient to signal that the return value should not be used
718 * as the proxy class loader.
719 */
720 private static ClassLoader loadProxyInterfaces(String[] interfaces,
721 ClassLoader loader,
722 Class[] classObjs,
723 boolean[] nonpublic)
724 throws ClassNotFoundException
725 {
726 /* loader of a non-public interface class */
727 ClassLoader nonpublicLoader = null;
728
729 for (int i = 0; i < interfaces.length; i++) {
730 Class cl =
731 (classObjs[i] = Class.forName(interfaces[i], false, loader));
732
733 if (!Modifier.isPublic(cl.getModifiers())) {
734 ClassLoader current = cl.getClassLoader();
735 if (loaderLog.isLoggable(Log.VERBOSE)) {
736 loaderLog.log(Log.VERBOSE,
737 "non-public interface \"" + interfaces[i] +
738 "\" defined by " + current);
739 }
740 if (!nonpublic[0]) {
741 nonpublicLoader = current;
742 nonpublic[0] = true;
743 } else if (current != nonpublicLoader) {
744 throw new IllegalAccessError(
745 "non-public interfaces defined in different " +
746 "class loaders");
747 }
748 }
749 }
750 return nonpublicLoader;
761 synchronized (pathToURLsCache) {
762 Object[] v = pathToURLsCache.get(path);
763 if (v != null) {
764 return ((URL[])v[0]);
765 }
766 }
767 StringTokenizer st = new StringTokenizer(path); // divide by spaces
768 URL[] urls = new URL[st.countTokens()];
769 for (int i = 0; st.hasMoreTokens(); i++) {
770 urls[i] = new URL(st.nextToken());
771 }
772 synchronized (pathToURLsCache) {
773 pathToURLsCache.put(path,
774 new Object[] {urls, new SoftReference<String>(path)});
775 }
776 return urls;
777 }
778
779 /** map from weak(key=string) to [URL[], soft(key)] */
780 private static final Map<String, Object[]> pathToURLsCache
781 = new WeakHashMap<String, Object[]>(5);
782
783 /**
784 * Convert an array of URL objects into a corresponding string
785 * containing a space-separated list of URLs.
786 *
787 * Note that if the array has zero elements, the return value is
788 * null, not the empty string.
789 */
790 private static String urlsToPath(URL[] urls) {
791 if (urls.length == 0) {
792 return null;
793 } else if (urls.length == 1) {
794 return urls[0].toExternalForm();
795 } else {
796 StringBuffer path = new StringBuffer(urls[0].toExternalForm());
797 for (int i = 1; i < urls.length; i++) {
798 path.append(' ');
799 path.append(urls[i].toExternalForm());
800 }
801 return path.toString();
1154 * class loader.
1155 */
1156 annotation = urlsToPath(urls);
1157 }
1158
1159 /**
1160 * Return the string to be annotated with all classes loaded from
1161 * this class loader.
1162 */
1163 public String getClassAnnotation() {
1164 return annotation;
1165 }
1166
1167 /**
1168 * Check that the current access control context has all of the
1169 * permissions necessary to load classes from this loader.
1170 */
1171 private void checkPermissions() {
1172 SecurityManager sm = System.getSecurityManager();
1173 if (sm != null) { // should never be null?
1174 Enumeration enum_ = permissions.elements();
1175 while (enum_.hasMoreElements()) {
1176 sm.checkPermission((Permission) enum_.nextElement());
1177 }
1178 }
1179 }
1180
1181 /**
1182 * Return the permissions to be granted to code loaded from the
1183 * given code source.
1184 */
1185 protected PermissionCollection getPermissions(CodeSource codesource) {
1186 PermissionCollection perms = super.getPermissions(codesource);
1187 /*
1188 * Grant the same permissions that URLClassLoader would grant.
1189 */
1190 return perms;
1191 }
1192
1193 /**
1194 * Return a string representation of this loader (useful for
1195 * debugging).
1196 */
|
95
96 /** table of class loaders that use codebase property for annotation */
97 private static final Map<ClassLoader, Void> codebaseLoaders =
98 Collections.synchronizedMap(new IdentityHashMap<ClassLoader, Void>(5));
99 static {
100 for (ClassLoader codebaseLoader = ClassLoader.getSystemClassLoader();
101 codebaseLoader != null;
102 codebaseLoader = codebaseLoader.getParent())
103 {
104 codebaseLoaders.put(codebaseLoader, null);
105 }
106 }
107
108 /**
109 * table mapping codebase URL path and context class loader pairs
110 * to class loader instances. Entries hold class loaders with weak
111 * references, so this table does not prevent loaders from being
112 * garbage collected.
113 */
114 private static final HashMap<LoaderKey, LoaderEntry> loaderTable
115 = new HashMap<>(5);
116
117 /** reference queue for cleared class loader entries */
118 private static final ReferenceQueue<Loader> refQueue
119 = new ReferenceQueue<>();
120
121 /*
122 * Disallow anyone from creating one of these.
123 */
124 private LoaderHandler() {}
125
126 /**
127 * Returns an array of URLs initialized with the value of the
128 * java.rmi.server.codebase property as the URL path.
129 */
130 private static synchronized URL[] getDefaultCodebaseURLs()
131 throws MalformedURLException
132 {
133 /*
134 * If it hasn't already been done, convert the codebase property
135 * into an array of URLs; this may throw a MalformedURLException.
136 */
137 if (codebaseURLs == null) {
138 if (codebaseProperty != null) {
139 codebaseURLs = pathToURLs(codebaseProperty);
140 } else {
141 codebaseURLs = new URL[0];
142 }
143 }
144 return codebaseURLs;
145 }
146
147 /**
148 * Load a class from a network location (one or more URLs),
149 * but first try to resolve the named class through the given
150 * "default loader".
151 */
152 public static Class<?> loadClass(String codebase, String name,
153 ClassLoader defaultLoader)
154 throws MalformedURLException, ClassNotFoundException
155 {
156 if (loaderLog.isLoggable(Log.BRIEF)) {
157 loaderLog.log(Log.BRIEF,
158 "name = \"" + name + "\", " +
159 "codebase = \"" + (codebase != null ? codebase : "") + "\"" +
160 (defaultLoader != null ?
161 ", defaultLoader = " + defaultLoader : ""));
162 }
163
164 URL[] urls;
165 if (codebase != null) {
166 urls = pathToURLs(codebase);
167 } else {
168 urls = getDefaultCodebaseURLs();
169 }
170
171 if (defaultLoader != null) {
172 try {
173 Class<?> c = Class.forName(name, false, defaultLoader);
174 if (loaderLog.isLoggable(Log.VERBOSE)) {
175 loaderLog.log(Log.VERBOSE,
176 "class \"" + name + "\" found via defaultLoader, " +
177 "defined by " + c.getClassLoader());
178 }
179 return c;
180 } catch (ClassNotFoundException e) {
181 }
182 }
183
184 return loadClass(urls, name);
185 }
186
187 /**
188 * Returns the class annotation (representing the location for
189 * a class) that RMI will use to annotate the call stream when
190 * marshalling objects of the given class.
191 */
192 public static String getClassAnnotation(Class<?> cl) {
193 String name = cl.getName();
194
195 /*
196 * Class objects for arrays of primitive types never need an
197 * annotation, because they never need to be (or can be) downloaded.
198 *
199 * REMIND: should we (not) be annotating classes that are in
200 * "java.*" packages?
201 */
202 int nameLength = name.length();
203 if (nameLength > 0 && name.charAt(0) == '[') {
204 // skip past all '[' characters (see bugid 4211906)
205 int i = 1;
206 while (nameLength > i && name.charAt(i) == '[') {
207 i++;
208 }
209 if (nameLength > i && name.charAt(i) != 'L') {
210 return null;
211 }
212 }
244 * we must verify that the current access control context
245 * has permission to know all of these URLs.
246 */
247 SecurityManager sm = System.getSecurityManager();
248 if (sm != null) {
249 Permissions perms = new Permissions();
250 for (int i = 0; i < urls.length; i++) {
251 Permission p =
252 urls[i].openConnection().getPermission();
253 if (p != null) {
254 if (!perms.implies(p)) {
255 sm.checkPermission(p);
256 perms.add(p);
257 }
258 }
259 }
260 }
261
262 annotation = urlsToPath(urls);
263 }
264 } catch (SecurityException | IOException e) {
265 /*
266 * SecurityException: If access was denied to the knowledge of
267 * the class loader's URLs, fall back to the default behavior.
268 *
269 * IOException: This shouldn't happen, although it is declared
270 * to be thrown by openConnection() and getPermission(). If it
271 * does happen, forget about this class loader's URLs and
272 * fall back to the default behavior.
273 */
274 }
275 }
276
277 if (annotation != null) {
278 return annotation;
279 } else {
280 return codebaseProperty; // REMIND: does this make sense??
281 }
282 }
283
284 /**
285 * Returns a classloader that loads classes from the given codebase URL
286 * path. The parent classloader of the returned classloader is the
287 * context class loader.
288 */
289 public static ClassLoader getClassLoader(String codebase)
290 throws MalformedURLException
339 URL[] urls = ((Loader) loader).getURLs();
340 if (urls.length > 0) {
341 return urls[0];
342 }
343 }
344 return null;
345 }
346
347 /**
348 * Register a class loader as one whose classes should always be
349 * annotated with the value of the "java.rmi.server.codebase" property.
350 */
351 public static void registerCodebaseLoader(ClassLoader loader) {
352 codebaseLoaders.put(loader, null);
353 }
354
355 /**
356 * Load a class from the RMI class loader corresponding to the given
357 * codebase URL path in the current execution context.
358 */
359 private static Class<?> loadClass(URL[] urls, String name)
360 throws ClassNotFoundException
361 {
362 ClassLoader parent = getRMIContextClassLoader();
363 if (loaderLog.isLoggable(Log.VERBOSE)) {
364 loaderLog.log(Log.VERBOSE,
365 "(thread context class loader: " + parent + ")");
366 }
367
368 /*
369 * If no security manager is set, disable access to RMI class
370 * loaders and simply delegate request to the parent loader
371 * (see bugid 4140511).
372 */
373 SecurityManager sm = System.getSecurityManager();
374 if (sm == null) {
375 try {
376 Class<?> c = Class.forName(name, false, parent);
377 if (loaderLog.isLoggable(Log.VERBOSE)) {
378 loaderLog.log(Log.VERBOSE,
379 "class \"" + name + "\" found via " +
380 "thread context class loader " +
381 "(no security manager: codebase disabled), " +
382 "defined by " + c.getClassLoader());
383 }
384 return c;
385 } catch (ClassNotFoundException e) {
386 if (loaderLog.isLoggable(Log.BRIEF)) {
387 loaderLog.log(Log.BRIEF,
388 "class \"" + name + "\" not found via " +
389 "thread context class loader " +
390 "(no security manager: codebase disabled)", e);
391 }
392 throw new ClassNotFoundException(e.getMessage() +
393 " (no security manager: RMI class loader disabled)",
394 e.getException());
395 }
396 }
405 if (loader != null) {
406 /*
407 * Verify that the caller has permission to access this loader.
408 */
409 loader.checkPermissions();
410 }
411 } catch (SecurityException e) {
412 /*
413 * If the current access control context does not have permission
414 * to access all of the URLs in the codebase path, wrap the
415 * resulting security exception in a ClassNotFoundException, so
416 * the caller can handle this outcome just like any other class
417 * loading failure (see bugid 4146529).
418 */
419 try {
420 /*
421 * But first, check to see if the named class could have been
422 * resolved without the security-offending codebase anyway;
423 * if so, return successfully (see bugids 4191926 & 4349670).
424 */
425 Class<?> c = Class.forName(name, false, parent);
426 if (loaderLog.isLoggable(Log.VERBOSE)) {
427 loaderLog.log(Log.VERBOSE,
428 "class \"" + name + "\" found via " +
429 "thread context class loader " +
430 "(access to codebase denied), " +
431 "defined by " + c.getClassLoader());
432 }
433 return c;
434 } catch (ClassNotFoundException unimportant) {
435 /*
436 * Presumably the security exception is the more important
437 * exception to report in this case.
438 */
439 if (loaderLog.isLoggable(Log.BRIEF)) {
440 loaderLog.log(Log.BRIEF,
441 "class \"" + name + "\" not found via " +
442 "thread context class loader " +
443 "(access to codebase denied)", e);
444 }
445 throw new ClassNotFoundException(
446 "access to class loader denied", e);
447 }
448 }
449
450 try {
451 Class<?> c = Class.forName(name, false, loader);
452 if (loaderLog.isLoggable(Log.VERBOSE)) {
453 loaderLog.log(Log.VERBOSE,
454 "class \"" + name + "\" " + "found via codebase, " +
455 "defined by " + c.getClassLoader());
456 }
457 return c;
458 } catch (ClassNotFoundException e) {
459 if (loaderLog.isLoggable(Log.BRIEF)) {
460 loaderLog.log(Log.BRIEF,
461 "class \"" + name + "\" not found via codebase", e);
462 }
463 throw e;
464 }
465 }
466
467 /**
468 * Define and return a dynamic proxy class in a class loader with
469 * URLs supplied in the given location. The proxy class will
470 * implement interface classes named by the given array of
471 * interface names.
472 */
473 public static Class<?> loadProxyClass(String codebase, String[] interfaces,
474 ClassLoader defaultLoader)
475 throws MalformedURLException, ClassNotFoundException
476 {
477 if (loaderLog.isLoggable(Log.BRIEF)) {
478 loaderLog.log(Log.BRIEF,
479 "interfaces = " + Arrays.asList(interfaces) + ", " +
480 "codebase = \"" + (codebase != null ? codebase : "") + "\"" +
481 (defaultLoader != null ?
482 ", defaultLoader = " + defaultLoader : ""));
483 }
484
485 /*
486 * This method uses a fairly complex algorithm to load the
487 * proxy class and its interface classes in order to maximize
488 * the likelihood that the proxy's codebase annotation will be
489 * preserved. The algorithm is (assuming that all of the
490 * proxy interface classes are public):
491 *
492 * If the default loader is not null, try to load the proxy
493 * interfaces through that loader. If the interfaces can be
518 ClassLoader parent = getRMIContextClassLoader();
519 if (loaderLog.isLoggable(Log.VERBOSE)) {
520 loaderLog.log(Log.VERBOSE,
521 "(thread context class loader: " + parent + ")");
522 }
523
524 URL[] urls;
525 if (codebase != null) {
526 urls = pathToURLs(codebase);
527 } else {
528 urls = getDefaultCodebaseURLs();
529 }
530
531 /*
532 * If no security manager is set, disable access to RMI class
533 * loaders and use the would-de parent instead.
534 */
535 SecurityManager sm = System.getSecurityManager();
536 if (sm == null) {
537 try {
538 Class<?> c = loadProxyClass(interfaces, defaultLoader, parent,
539 false);
540 if (loaderLog.isLoggable(Log.VERBOSE)) {
541 loaderLog.log(Log.VERBOSE,
542 "(no security manager: codebase disabled) " +
543 "proxy class defined by " + c.getClassLoader());
544 }
545 return c;
546 } catch (ClassNotFoundException e) {
547 if (loaderLog.isLoggable(Log.BRIEF)) {
548 loaderLog.log(Log.BRIEF,
549 "(no security manager: codebase disabled) " +
550 "proxy class resolution failed", e);
551 }
552 throw new ClassNotFoundException(e.getMessage() +
553 " (no security manager: RMI class loader disabled)",
554 e.getException());
555 }
556 }
557
558 /*
565 if (loader != null) {
566 /*
567 * Verify that the caller has permission to access this loader.
568 */
569 loader.checkPermissions();
570 }
571 } catch (SecurityException e) {
572 /*
573 * If the current access control context does not have permission
574 * to access all of the URLs in the codebase path, wrap the
575 * resulting security exception in a ClassNotFoundException, so
576 * the caller can handle this outcome just like any other class
577 * loading failure (see bugid 4146529).
578 */
579 try {
580 /*
581 * But first, check to see if the proxy class could have been
582 * resolved without the security-offending codebase anyway;
583 * if so, return successfully (see bugids 4191926 & 4349670).
584 */
585 Class<?> c = loadProxyClass(interfaces, defaultLoader, parent,
586 false);
587 if (loaderLog.isLoggable(Log.VERBOSE)) {
588 loaderLog.log(Log.VERBOSE,
589 "(access to codebase denied) " +
590 "proxy class defined by " + c.getClassLoader());
591 }
592 return c;
593 } catch (ClassNotFoundException unimportant) {
594 /*
595 * Presumably the security exception is the more important
596 * exception to report in this case.
597 */
598 if (loaderLog.isLoggable(Log.BRIEF)) {
599 loaderLog.log(Log.BRIEF,
600 "(access to codebase denied) " +
601 "proxy class resolution failed", e);
602 }
603 throw new ClassNotFoundException(
604 "access to class loader denied", e);
605 }
606 }
607
608 try {
609 Class<?> c = loadProxyClass(interfaces, defaultLoader, loader, true);
610 if (loaderLog.isLoggable(Log.VERBOSE)) {
611 loaderLog.log(Log.VERBOSE,
612 "proxy class defined by " + c.getClassLoader());
613 }
614 return c;
615 } catch (ClassNotFoundException e) {
616 if (loaderLog.isLoggable(Log.BRIEF)) {
617 loaderLog.log(Log.BRIEF,
618 "proxy class resolution failed", e);
619 }
620 throw e;
621 }
622 }
623
624 /**
625 * Define a proxy class in the default loader if appropriate.
626 * Define the class in an RMI class loader otherwise. The proxy
627 * class will implement classes which are named in the supplied
628 * interfaceNames.
629 */
630 private static Class<?> loadProxyClass(String[] interfaceNames,
631 ClassLoader defaultLoader,
632 ClassLoader codebaseLoader,
633 boolean preferCodebase)
634 throws ClassNotFoundException
635 {
636 ClassLoader proxyLoader = null;
637 Class<?>[] classObjs = new Class<?>[interfaceNames.length];
638 boolean[] nonpublic = { false };
639
640 defaultLoaderCase:
641 if (defaultLoader != null) {
642 try {
643 proxyLoader =
644 loadProxyInterfaces(interfaceNames, defaultLoader,
645 classObjs, nonpublic);
646 if (loaderLog.isLoggable(Log.VERBOSE)) {
647 ClassLoader[] definingLoaders =
648 new ClassLoader[classObjs.length];
649 for (int i = 0; i < definingLoaders.length; i++) {
650 definingLoaders[i] = classObjs[i].getClassLoader();
651 }
652 loaderLog.log(Log.VERBOSE,
653 "proxy interfaces found via defaultLoader, " +
654 "defined by " + Arrays.asList(definingLoaders));
655 }
656 } catch (ClassNotFoundException e) {
657 break defaultLoaderCase;
673 classObjs, nonpublic);
674 if (loaderLog.isLoggable(Log.VERBOSE)) {
675 ClassLoader[] definingLoaders = new ClassLoader[classObjs.length];
676 for (int i = 0; i < definingLoaders.length; i++) {
677 definingLoaders[i] = classObjs[i].getClassLoader();
678 }
679 loaderLog.log(Log.VERBOSE,
680 "proxy interfaces found via codebase, " +
681 "defined by " + Arrays.asList(definingLoaders));
682 }
683 if (!nonpublic[0]) {
684 proxyLoader = codebaseLoader;
685 }
686 return loadProxyClass(proxyLoader, classObjs);
687 }
688
689 /**
690 * Define a proxy class in the given class loader. The proxy
691 * class will implement the given interfaces Classes.
692 */
693 private static Class<?> loadProxyClass(ClassLoader loader, Class[] interfaces)
694 throws ClassNotFoundException
695 {
696 try {
697 return Proxy.getProxyClass(loader, interfaces);
698 } catch (IllegalArgumentException e) {
699 throw new ClassNotFoundException(
700 "error creating dynamic proxy class", e);
701 }
702 }
703
704 /*
705 * Load Class objects for the names in the interfaces array fron
706 * the given class loader.
707 *
708 * We pass classObjs and nonpublic arrays to avoid needing a
709 * multi-element return value. nonpublic is an array to enable
710 * the method to take a boolean argument by reference.
711 *
712 * nonpublic array is needed to signal when the return value of
713 * this method should be used as the proxy class loader. Because
714 * null represents a valid class loader, that value is
715 * insufficient to signal that the return value should not be used
716 * as the proxy class loader.
717 */
718 private static ClassLoader loadProxyInterfaces(String[] interfaces,
719 ClassLoader loader,
720 Class[] classObjs,
721 boolean[] nonpublic)
722 throws ClassNotFoundException
723 {
724 /* loader of a non-public interface class */
725 ClassLoader nonpublicLoader = null;
726
727 for (int i = 0; i < interfaces.length; i++) {
728 Class<?> cl =
729 (classObjs[i] = Class.forName(interfaces[i], false, loader));
730
731 if (!Modifier.isPublic(cl.getModifiers())) {
732 ClassLoader current = cl.getClassLoader();
733 if (loaderLog.isLoggable(Log.VERBOSE)) {
734 loaderLog.log(Log.VERBOSE,
735 "non-public interface \"" + interfaces[i] +
736 "\" defined by " + current);
737 }
738 if (!nonpublic[0]) {
739 nonpublicLoader = current;
740 nonpublic[0] = true;
741 } else if (current != nonpublicLoader) {
742 throw new IllegalAccessError(
743 "non-public interfaces defined in different " +
744 "class loaders");
745 }
746 }
747 }
748 return nonpublicLoader;
759 synchronized (pathToURLsCache) {
760 Object[] v = pathToURLsCache.get(path);
761 if (v != null) {
762 return ((URL[])v[0]);
763 }
764 }
765 StringTokenizer st = new StringTokenizer(path); // divide by spaces
766 URL[] urls = new URL[st.countTokens()];
767 for (int i = 0; st.hasMoreTokens(); i++) {
768 urls[i] = new URL(st.nextToken());
769 }
770 synchronized (pathToURLsCache) {
771 pathToURLsCache.put(path,
772 new Object[] {urls, new SoftReference<String>(path)});
773 }
774 return urls;
775 }
776
777 /** map from weak(key=string) to [URL[], soft(key)] */
778 private static final Map<String, Object[]> pathToURLsCache
779 = new WeakHashMap<>(5);
780
781 /**
782 * Convert an array of URL objects into a corresponding string
783 * containing a space-separated list of URLs.
784 *
785 * Note that if the array has zero elements, the return value is
786 * null, not the empty string.
787 */
788 private static String urlsToPath(URL[] urls) {
789 if (urls.length == 0) {
790 return null;
791 } else if (urls.length == 1) {
792 return urls[0].toExternalForm();
793 } else {
794 StringBuffer path = new StringBuffer(urls[0].toExternalForm());
795 for (int i = 1; i < urls.length; i++) {
796 path.append(' ');
797 path.append(urls[i].toExternalForm());
798 }
799 return path.toString();
1152 * class loader.
1153 */
1154 annotation = urlsToPath(urls);
1155 }
1156
1157 /**
1158 * Return the string to be annotated with all classes loaded from
1159 * this class loader.
1160 */
1161 public String getClassAnnotation() {
1162 return annotation;
1163 }
1164
1165 /**
1166 * Check that the current access control context has all of the
1167 * permissions necessary to load classes from this loader.
1168 */
1169 private void checkPermissions() {
1170 SecurityManager sm = System.getSecurityManager();
1171 if (sm != null) { // should never be null?
1172 Enumeration<Permission> enum_ = permissions.elements();
1173 while (enum_.hasMoreElements()) {
1174 sm.checkPermission(enum_.nextElement());
1175 }
1176 }
1177 }
1178
1179 /**
1180 * Return the permissions to be granted to code loaded from the
1181 * given code source.
1182 */
1183 protected PermissionCollection getPermissions(CodeSource codesource) {
1184 PermissionCollection perms = super.getPermissions(codesource);
1185 /*
1186 * Grant the same permissions that URLClassLoader would grant.
1187 */
1188 return perms;
1189 }
1190
1191 /**
1192 * Return a string representation of this loader (useful for
1193 * debugging).
1194 */
|