1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package java.lang;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.lang.reflect.Constructor;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25 import java.nio.ByteBuffer;
26 import java.net.URLClassLoader;
27 import java.security.AccessController;
28 import java.security.CodeSource;
29 import java.security.PrivilegedActionException;
30 import java.security.PrivilegedExceptionAction;
31 import java.security.ProtectionDomain;
32 import java.security.cert.Certificate;
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.Enumeration;
36 import java.util.HashMap;
37 import java.util.Hashtable;
38 import java.util.NoSuchElementException;
39
40 import org.apache.harmony.lang.RuntimePermissionCollection;
41 import org.apache.harmony.misc.EmptyEnum;
42 import org.apache.harmony.lang.ClassLoaderInfo;
43 import org.apache.harmony.vm.VMStack;
44
45 /**
46 * Base class for all class loaders
47 *
48 * @author Evgueni Brevnov
49 */
50 public abstract class ClassLoader {
51
52 /**
53 * default protection domain.
54 */
55 private ProtectionDomain defaultDomain;
56
57 /**
58 * system default class loader. It is initialized while
59 * getSystemClassLoader(..) method is executing.
60 */
61 private static ClassLoader systemClassLoader = null;
62
63 /**
64 * empty set of certificates
65 */
66 private static final Certificate[] EMPTY_CERTIFICATES = new Certificate[0];
67
68 /**
69 * this field has false as default value, it becomes true if system class
70 * loader is initialized.
71 */
72 private static boolean initialized = false;
73
74 /**
75 * package private to access from the java.lang.Class class. The following
76 * mapping is used <String name, Boolean flag>, where name - class name,
77 * flag - true if assertion is enabled, false if disabled.
78 */
79 Hashtable<String, Boolean> classAssertionStatus;
80
81 /**
82 * package private to access from the java.lang.Class class. The following
83 * mapping is used <String name, Object[] signers>, where name - class name,
84 * signers - array of signers.
85 */
86 Hashtable<String, Object[]> classSigners;
87
88 /**
89 * package private to access from the java.lang.Class class.
90 */
91 int defaultAssertionStatus;
92 boolean clearAssertionStatus;
93
94 /**
95 * package private to access from the java.lang.Class class. The following
96 * mapping is used <String name, Boolean flag>, where name - package name,
97 * flag - true if assertion is enabled, false if disabled.
98 */
99 Hashtable<String, Boolean> packageAssertionStatus;
100
101 /**
102 * packages defined by this class loader are stored in this hash. The
103 * following mapping is used <String name, Package pkg>, where name -
104 * package name, pkg - corresponding package.
105 */
106 private final HashMap<String, Package> definedPackages;
107
108 /**
109 * The class registry, provides strong referencing between the classloader
110 * and it's defined classes. Intended for class unloading implementation.
111 * @see java.lang.Class#definingLoader
112 * @see #registerLoadedClass()
113 */
114 private ArrayList<Class<?>> loadedClasses = new ArrayList<Class<?>>();
115
116 /**
117 * package private to access from the java.lang.Class class. The following
118 * mapping is used <String name, Certificate[] certificates>, where name -
119 * the name of a package, certificates - array of certificates.
120 */
121 private final Hashtable<String, Certificate[]> packageCertificates =
122 new Hashtable<String, Certificate[]>();
123
124 /**
125 * parent class loader
126 */
127 private final ClassLoader parentClassLoader;
128
129 protected ClassLoader() {
130 this(getSystemClassLoader());
131 }
132
133 protected ClassLoader(ClassLoader parent) {
134 SecurityManager sc = System.getSecurityManager();
135 if (sc != null) {
136 sc.checkCreateClassLoader();
137 }
138 parentClassLoader = parent;
139 // this field is used to determine whether class loader was initialized
140 // properly.
141 definedPackages = new HashMap<String, Package>();
142 }
143
144 public static ClassLoader getSystemClassLoader() {
145 if (!initialized) {
146 // we assume only one thread will initialize system class loader. So
147 // we don't synchronize initSystemClassLoader() method.
148 initSystemClassLoader();
149 // system class loader is initialized properly.
150 initialized = true;
151 // setContextClassLoader(...) method throws SecurityException if
152 // current thread isn't allowed to set systemClassLoader as a
153 // context class loader. Actually, it is abnormal situation if
154 // thread can not change his own context class loader.
155 // Thread.currentThread().setContextClassLoader(systemClassLoader);
156 }
157 //assert initialized;
158 SecurityManager sc = System.getSecurityManager();
159 if (sc != null) {
160 // we use VMClassRegistry.getClassLoader(...) method instead of
161 // Class.getClassLoader() due to avoid redundant security
162 // checking
163 ClassLoader callerLoader = VMClassRegistry.getClassLoader(VMStack
164 .getCallerClass(0));
165 if (callerLoader != null && callerLoader != systemClassLoader) {
166 sc.checkPermission(RuntimePermissionCollection.GET_CLASS_LOADER_PERMISSION);
167 }
168 }
169 return systemClassLoader;
170 }
171
172 public static URL getSystemResource(String name) {
173 return getSystemClassLoader().getResource(name);
174 }
175
176 public static InputStream getSystemResourceAsStream(String name) {
177 return getSystemClassLoader().getResourceAsStream(name);
178 }
179
180 public static Enumeration<URL> getSystemResources(String name)
181 throws IOException {
182 return getSystemClassLoader().getResources(name);
183 }
184
185 public void clearAssertionStatus() {
186 clearAssertionStatus = true;
187 defaultAssertionStatus = -1;
188 packageAssertionStatus = null;
189 classAssertionStatus = null;
190 }
191
192 public final ClassLoader getParent() {
193 SecurityManager sc = System.getSecurityManager();
194 if (sc != null) {
195 ClassLoader callerLoader = VMClassRegistry.getClassLoader(VMStack
196 .getCallerClass(0));
197 if (callerLoader != null && !callerLoader.isSameOrAncestor(this)) {
198 sc.checkPermission(RuntimePermissionCollection.GET_CLASS_LOADER_PERMISSION);
199 }
200 }
201 return parentClassLoader;
202 }
203
204 public URL getResource(String name) {
205 String nm = name.toString();
206 checkInitialized();
207 URL foundResource = (parentClassLoader == null)
208 ? BootstrapLoader.findResource(nm)
209 : parentClassLoader.getResource(nm);
210 return foundResource == null ? findResource(nm) : foundResource;
211 }
212
213 public InputStream getResourceAsStream(String name) {
214 URL foundResource = getResource(name);
215 if (foundResource != null) {
216 try {
217 return foundResource.openStream();
218 } catch (IOException e) {
219 }
220 }
221 return null;
222 }
223
224 public Enumeration<URL> getResources(String name) throws IOException {
225 checkInitialized();
226 ClassLoader cl = this;
227 final ArrayList<Enumeration<URL>> foundResources =
228 new ArrayList<Enumeration<URL>>();
229 Enumeration<URL> resourcesEnum;
230 do {
231 resourcesEnum = cl.findResources(name);
232 if (resourcesEnum != null && resourcesEnum.hasMoreElements()) {
233 foundResources.add(resourcesEnum);
234 }
235 } while ((cl = cl.parentClassLoader) != null);
236 resourcesEnum = BootstrapLoader.findResources(name);
237 if (resourcesEnum != null && resourcesEnum.hasMoreElements()) {
238 foundResources.add(resourcesEnum);
239 }
240 return new Enumeration<URL>() {
241
242 private int position = foundResources.size() - 1;
243
244 public boolean hasMoreElements() {
245 while (position >= 0) {
246 if (foundResources.get(position).hasMoreElements()) {
247 return true;
248 }
249 position--;
250 }
251 return false;
252 }
253
254 public URL nextElement() {
255 while (position >= 0) {
256 try {
257 return (foundResources.get(position)).nextElement();
258 } catch (NoSuchElementException e) {}
259 position--;
260 }
261 throw new NoSuchElementException();
262 }
263 };
264 }
265
266 public Class<?> loadClass(String name) throws ClassNotFoundException {
267 return loadClass(name, false);
268 }
269
270 public void setClassAssertionStatus(String name, boolean flag) {
271 if (name != null) {
272 Class.disableAssertions = false;
273 synchronized (definedPackages) {
274 if (classAssertionStatus == null) {
275 classAssertionStatus = new Hashtable<String, Boolean>();
276 }
277 }
278 classAssertionStatus.put(name, Boolean.valueOf(flag));
279 }
280 }
281
282 public void setDefaultAssertionStatus(boolean flag) {
283 if (flag) {
284 Class.disableAssertions = false;
285 }
286 defaultAssertionStatus = flag ? 1 : -1;
287 }
288
289 /**
290 * Empty string is used to denote default package.
291 */
292 public void setPackageAssertionStatus(String name, boolean flag) {
293 if (name == null) {
294 name = "";
295 }
296 Class.disableAssertions = false;
297 synchronized (definedPackages) {
298 if (packageAssertionStatus == null) {
299 packageAssertionStatus = new Hashtable<String, Boolean>();
300 }
301 }
302 packageAssertionStatus.put(name, Boolean.valueOf(flag));
303 }
304
305 @Deprecated
306 protected final Class<?> defineClass(byte[] data, int offset, int len)
307 throws ClassFormatError {
308 return defineClass(null, data, offset, len);
309 }
310
311 protected final Class<?> defineClass(String name, byte[] data, int offset, int len)
312 throws ClassFormatError {
313 return defineClass(name, data, offset, len, null);
314 }
315
316 /**
317 * Registers the defined class, invoked by VM.
318 * Intended for class unloading implementation.
319 */
320 @SuppressWarnings("unused")
321 private void registerLoadedClass(Class<?> clazz) {
322 synchronized (loadedClasses){
323 loadedClasses.add(clazz);
324 }
325 clazz.definingLoader = this;
326 }
327
328 protected final Class<?> defineClass(String name, ByteBuffer b, ProtectionDomain protectionDomain)
329 throws ClassFormatError {
330 byte[] data = b.array();
331 return defineClass(name, data, 0, data.length, protectionDomain);
332 }
333
334 protected final synchronized Class<?> defineClass(String name, byte[] data,
335 int offset, int len,
336 ProtectionDomain domain)
337 throws ClassFormatError {
338 checkInitialized();
339 if (name != null && name.indexOf('/') != -1) {
340 throw new NoClassDefFoundError(
341 "The name is expected in binary (canonical) form,"
342 + " therefore '/' symbols are not allowed: " + name);
343 }
344 if (offset < 0 || len < 0 || offset + len > data.length) {
345 throw new IndexOutOfBoundsException(
346 "Either offset or len is outside of the data array");
347 }
348 if (domain == null) {
349 if (defaultDomain == null) {
350 defaultDomain = new ProtectionDomain(
351 new CodeSource(null, (Certificate[])null), null, this, null);
352 }
353 domain = defaultDomain;
354 }
355 Certificate[] certs = null;
356 String packageName = null;
357 if (name != null) {
358 if (name.startsWith("java.")) {
359 throw new SecurityException(
360 "It is not allowed to define classes inside the java.* package: " + name);
361 }
362 int lastDot = name.lastIndexOf('.');
363 packageName = lastDot == -1 ? "" : name.substring(0, lastDot);
364 certs = getCertificates(packageName, domain.getCodeSource());
365 }
366 Class<?> clazz = defineClass0(name, data, offset, len);
367 clazz.setProtectionDomain(domain);
368 if (certs != null) {
369 packageCertificates.put(packageName, certs);
370 }
371 return clazz;
372 }
373
374 /**
375 * Loads new type into the classloader name space.
376 * The class loader is marked as defining class loader.
377 * @api2vm
378 */
379 private native Class<?> defineClass0(String name, byte[] data, int off, int len)
380 throws ClassFormatError;
381
382
383 protected Package definePackage(String name, String specTitle,
384 String specVersion, String specVendor,
385 String implTitle, String implVersion,
386 String implVendor, URL sealBase)
387 throws IllegalArgumentException {
388 synchronized (definedPackages) {
389 if (getPackage(name) != null) {
390 throw new IllegalArgumentException("Package " + name
391 + "has been already defined.");
392 }
393 Package pkg = new Package(this, name, specTitle, specVersion, specVendor,
394 implTitle, implVersion, implVendor, sealBase);
395 definedPackages.put(name, pkg);
396 return pkg;
397 }
398 }
399
400 protected Class<?> findClass(String name) throws ClassNotFoundException {
401 throw new ClassNotFoundException("Can not find class " + name);
402 }
403
404 protected String findLibrary(String name) {
405 return null;
406 }
407
408 protected final native Class<?> findLoadedClass(String name);
409
410 protected URL findResource(String name) {
411 return null;
412 }
413
414 protected Enumeration<URL> findResources(String name) throws IOException {
415 return EmptyEnum.getInstance();
416 }
417
418 protected final Class<?> findSystemClass(String name)
419 throws ClassNotFoundException {
420 return getSystemClassLoader().loadClass(name, false);
421 }
422
423 protected Package getPackage(String name) {
424 checkInitialized();
425 Package pkg = null;
426 if (name == null) {
427 throw new NullPointerException();
428 }
429 synchronized (definedPackages) {
430 pkg = definedPackages.get(name);
431 }
432 if (pkg == null) {
433 if (parentClassLoader == null) {
434 pkg = BootstrapLoader.getPackage(name);
435 } else {
436 pkg = parentClassLoader.getPackage(name);
437 }
438 }
439 return pkg;
440 }
441
442 protected Package[] getPackages() {
443 checkInitialized();
444 ArrayList<Package> packages = new ArrayList<Package>();
445 fillPackages(packages);
446 return packages.toArray(new Package[packages.size()]);
447 }
448
449 /**
450 * Registers this class loader as initiating for a class
451 * Declared as package private to use it from java.lang.Class.forName
452 */
453 native void registerInitiatedClass(Class<?> clazz);
454
455 protected synchronized Class<?> loadClass(String name, boolean resolve)
456 throws ClassNotFoundException {
457 checkInitialized();
458 if (name == null) {
459 throw new NullPointerException();
460 }
461 if(name.indexOf("/") != -1) {
462 throw new ClassNotFoundException(name);
463 }
464
465 Class<?> clazz = findLoadedClass(name);
466 if (clazz == null) {
467 if (parentClassLoader == null) {
468 clazz = VMClassRegistry.loadBootstrapClass(name);
469 } else {
470 try {
471 clazz = parentClassLoader.loadClass(name);
472 if(clazz != null) {
473 try {
474 VMStack.getCallerClass(0)
475 .asSubclass(ClassLoader.class);
476 } catch(ClassCastException ex) {
477 // caller class is not a subclass of
478 // java/lang/ClassLoader so register as
479 // initiating loader as we are called from
480 // outside of ClassLoader delegation chain
481 registerInitiatedClass(clazz);
482 }
483 }
484 } catch (ClassNotFoundException e) {
485 }
486 }
487 if (clazz == null) {
488 clazz = findClass(name);
489 if (clazz == null) {
490 throw new ClassNotFoundException(name);
491 }
492 }
493 }
494 if (resolve) {
495 resolveClass(clazz);
496 }
497 return clazz;
498 }
499
500 protected final void resolveClass(Class<?> clazz) {
501 if (clazz == null) {
502 throw new NullPointerException();
503 }
504 VMClassRegistry.linkClass(clazz);
505 }
506
507 protected final void setSigners(Class<?> clazz, Object[] signers) {
508 checkInitialized();
509 String name = clazz.getName();
510 ClassLoader classLoader = clazz.getClassLoaderImpl();
511 if (classLoader != null) {
512 if (classLoader.classSigners == null) {
513 classLoader.classSigners = new Hashtable<String, Object[]>();
514 }
515 classLoader.classSigners.put(name, signers);
516 }
517 }
518
519 /*
520 * NON API SECTION
521 */
522
523 final boolean isSameOrAncestor(ClassLoader loader) {
524 while (loader != null) {
525 if (this == loader) {
526 return true;
527 }
528 loader = loader.parentClassLoader;
529 }
530 return false;
531 }
532
533 /**
534 * This method should be called from each method that performs unsafe
535 * actions.
536 */
537 private void checkInitialized() {
538 if (definedPackages == null) {
539 throw new SecurityException(
540 "Class loader was not initialized properly.");
541 }
542 }
543
544 /**
545 * Neither certs1 nor certs2 cann't be equal to null.
546 */
547 private boolean compareAsSet(Certificate[] certs1, Certificate[] certs2) {
548 // TODO Is it possible to have multiple instances of same
549 // certificate in array? This implementation assumes that it is
550 // not possible.
551 if (certs1.length != certs1.length) {
552 return false;
553 }
554 if (certs1.length == 0) {
555 return true;
556 }
557 boolean[] hasEqual = new boolean[certs1.length];
558 for (int i = 0; i < certs1.length; i++) {
559 boolean isMatch = false;
560 for (int j = 0; j < certs2.length; j++) {
561 if (!hasEqual[j] && certs1[i].equals(certs2[j])) {
562 hasEqual[j] = isMatch = true;
563 break;
564 }
565 }
566 if (!isMatch) {
567 return false;
568 }
569 }
570 return true;
571 }
572
573 /**
574 * Initializes the system class loader.
575 */
576 @SuppressWarnings("unchecked")
577 private static void initSystemClassLoader() {
578 if (systemClassLoader != null) {
579 throw new IllegalStateException(
580 "Recursive invocation while initializing system class loader");
581 }
582 systemClassLoader = SystemClassLoader.getInstance();
583
584 String smName = System.getPropertyUnsecure("java.security.manager");
585 if (smName != null) {
586 try {
587 final Class<SecurityManager> smClass;
588 if ("".equals(smName) || "default".equalsIgnoreCase(smName)) {
589 smClass = java.lang.SecurityManager.class;
590 } else {
591 smClass = (Class<SecurityManager>)systemClassLoader.loadClass(smName);
592 if (!SecurityManager.class.isAssignableFrom(smClass)) {
593 throw new Error(smClass
594 + " must inherit java.lang.SecurityManager");
595 }
596 }
597 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
598 public Object run() throws Exception {
599 System.setSecurityManager(smClass.newInstance());
600 return null;
601 }
602 });
603 } catch (Exception e) {
604 throw (Error)new InternalError().initCause(e);
605 }
606 }
607
608 String className = System.getPropertyUnsecure("java.system.class.loader");
609 if (className != null) {
610 try {
611 final Class<?> userClassLoader = systemClassLoader
612 .loadClass(className);
613 if (!ClassLoader.class.isAssignableFrom(userClassLoader)) {
614 throw new Error(userClassLoader.toString()
615 + " must inherit java.lang.ClassLoader");
616 }
617 systemClassLoader = AccessController
618 .doPrivileged(new PrivilegedExceptionAction<ClassLoader>() {
619 public ClassLoader run() throws Exception {
620 Constructor c = userClassLoader
621 .getConstructor(ClassLoader.class);
622 return (ClassLoader)c.newInstance(systemClassLoader);
623 }
624 });
625 } catch (ClassNotFoundException e) {
626 throw new Error(e);
627 } catch (PrivilegedActionException e) {
628 throw new Error(e.getCause());
629 }
630 }
631 }
632
633 /**
634 * Helper method for the getPackages() method.
635 */
636 private void fillPackages(ArrayList<Package> packages) {
637 if (parentClassLoader == null) {
638 packages.addAll(BootstrapLoader.getPackages());
639 } else {
640 parentClassLoader.fillPackages(packages);
641 }
642 synchronized (definedPackages) {
643 packages.addAll(definedPackages.values());
644 }
645 }
646
647 /**
648 * Helper method for defineClass(...)
649 *
650 * @return null if the package already has the same set of certificates, if
651 * first class in the package is being defined then array of
652 * certificates extracted from codeSource is returned.
653 * @throws SecurityException if the package has different set of
654 * certificates than codeSource
655 */
656 private Certificate[] getCertificates(String packageName,
657 CodeSource codeSource) {
658 Certificate[] definedCerts = packageCertificates
659 .get(packageName);
660 Certificate[] classCerts = codeSource != null
661 ? codeSource.getCertificates() : EMPTY_CERTIFICATES;
662 classCerts = classCerts != null ? classCerts : EMPTY_CERTIFICATES;
663 // not first class in the package
664 if (definedCerts != null) {
665 if (!compareAsSet(definedCerts, classCerts)) {
666 throw new SecurityException("It is prohobited to define a "
667 + "class which has different set of signers than "
668 + "other classes in this package");
669 }
670 return null;
671 }
672 return classCerts;
673 }
674
675 /**
676 * Helper method to avoid StringTokenizer using.
677 */
678 private static String[] fracture(String str, String sep) {
679 if (str.length() == 0) {
680 return new String[0];
681 }
682 ArrayList<String> res = new ArrayList<String>();
683 int in = 0;
684 int curPos = 0;
685 int i = str.indexOf(sep);
686 int len = sep.length();
687 while (i != -1) {
688 String s = str.substring(curPos, i);
689 res.add(s);
690 in++;
691 curPos = i + len;
692 i = str.indexOf(sep, curPos);
693 }
694
695 len = str.length();
696 if (curPos <= len) {
697 String s = str.substring(curPos, len);
698 in++;
699 res.add(s);
700 }
701
702 return res.toArray(new String[in]);
703 }
704
705 /* IBM SPECIFIC PART */
706
707 static final ClassLoader getStackClassLoader(int depth) {
708 Class<?> clazz = VMStack.getCallerClass(depth);
709 return clazz != null ? clazz.getClassLoaderImpl() : null;
710 }
711
712 final boolean isSystemClassLoader () {
713 return ClassLoaderInfo.isSystemClassLoader(this);
714 }
715
716 static final void loadLibraryWithClassLoader (String libName, ClassLoader loader) {
717 SecurityManager sc = System.getSecurityManager();
718 if (sc != null) {
719 sc.checkLink(libName);
720 }
721 if (loader != null) {
722 String fullLibName = loader.findLibrary(libName);
723 if (fullLibName != null) {
724 loadLibrary(fullLibName, loader, null);
725 return;
726 }
727 }
728 String path = System.getProperty("java.library.path", "");
729 path += System.getProperty("vm.boot.library.path", "");
730 loadLibrary(libName, loader, path);
731 }
732
733 static final void loadLibrary (String libName, ClassLoader loader, String libraryPath) {
734 SecurityManager sc = System.getSecurityManager();
735 if (sc != null) {
736 sc.checkLink(libName);
737 }
738 String pathSeparator = System.getProperty("path.separator");
739 String fileSeparator = System.getProperty("file.separator");
740 String st[] = fracture(libraryPath, pathSeparator);
741 int l = st.length;
742 for (int i = 0; i < l; i++) {
743 try {
744 VMClassRegistry.loadLibrary(st[i] + fileSeparator + libName, loader);
745 return;
746 } catch (UnsatisfiedLinkError e) {
747 }
748 }
749 throw new UnsatisfiedLinkError(libName);
750 }
751
752 /* END OF IBM SPECIFIC PART */
753
754 static final class BootstrapLoader {
755
756 // TODO avoid security checking
757 private static final String bootstrapPath = System
758 .getProperty("vm.boot.class.path", "");
759
760 private static URLClassLoader resourceFinder = null;
761
762 private static final HashMap<String, Package> systemPackages =
763 new HashMap<String, Package>();
764
765 /**
766 * This class contains static methods only. So it should not be
767 * instantiated.
768 */
769 private BootstrapLoader() {
770 }
771
772 public static URL findResource(String name) {
773 if (resourceFinder == null) {
774 initResourceFinder();
775 }
776 return resourceFinder.findResource(name);
777 }
778
779 public static Enumeration<URL> findResources(String name) throws IOException {
780 if (resourceFinder == null) {
781 initResourceFinder();
782 }
783 return resourceFinder.findResources(name);
784 }
785
786 public static Package getPackage(String name) {
787 synchronized (systemPackages) {
788 updatePackages();
789 return systemPackages.get(name.toString());
790 }
791 }
792
793 public static Collection<Package> getPackages() {
794 synchronized (systemPackages) {
795 updatePackages();
796 return systemPackages.values();
797 }
798 }
799
800 private static void initResourceFinder() {
801 synchronized (bootstrapPath) {
802 if (resourceFinder != null) {
803 return;
804 }
805 // -Xbootclasspath:"" should be interpreted as nothing defined,
806 // like we do below:
807 String st[] = fracture(bootstrapPath, File.pathSeparator);
808 int l = st.length;
809 ArrayList<URL> urlList = new ArrayList<URL>();
810 for (int i = 0; i < l; i++) {
811 try {
812 urlList.add(new File(st[i]).toURI().toURL());
813 } catch (MalformedURLException e) {
814 }
815 }
816 URL[] urls = new URL[urlList.size()];
817 resourceFinder = new URLClassLoader(urlList
818 .toArray(urls), null);
819 }
820 }
821
822 private static void updatePackages() {
823 String[][] packages = VMClassRegistry.getSystemPackages(systemPackages.size());
824 if (null == packages) {
825 return;
826 }
827 for (int i = 0; i < packages.length; i++) {
828
829 String name = packages[i][0];
830 if (systemPackages.containsKey(name)) {
831 continue;
832 }
833
834 String jarURL = packages[i][1];
835 systemPackages.put(name, new Package(null, name, jarURL));
836 }
837 }
838 }
839
840 private static final class SystemClassLoader extends URLClassLoader {
841
842 private boolean checkingPackageAccess = false;
843
844 private SystemClassLoader(URL[] urls, ClassLoader parent) {
845 super(urls, parent);
846 }
847
848 @Override
849 protected java.security.PermissionCollection getPermissions(CodeSource codesource) {
850 java.security.PermissionCollection pc = super.getPermissions(codesource);
851 pc.add(org.apache.harmony.lang.RuntimePermissionCollection.EXIT_VM_PERMISSION);
852 return pc;
853 }
854
855 @Override
856 protected synchronized Class<?> loadClass(String className,
857 boolean resolveClass) throws ClassNotFoundException {
858 SecurityManager sm = System.getSecurityManager();
859 if (sm != null && !checkingPackageAccess) {
860 int index = className.lastIndexOf('.');
861 if (index > 0) { // skip if class is from a default package
862 try {
863 checkingPackageAccess = true;
864 sm.checkPackageAccess(className.substring(0, index));
865 } finally {
866 checkingPackageAccess = false;
867 }
868 }
869 }
870 return super.loadClass(className, resolveClass);
871 }
872
873 private static URLClassLoader instance;
874
875 static {
876 ArrayList<URL> urlList = new ArrayList<URL>();
877 // TODO avoid security checking?
878 String extDirs = System.getProperty("java.ext.dirs", "");
879
880 // -Djava.ext.dirs="" should be interpreted as nothing defined,
881 // like we do below:
882 String st[] = fracture(extDirs, File.pathSeparator);
883 int l = st.length;
884 for (int i = 0; i < l; i++) {
885 try {
886 File dir = new File(st[i]).getAbsoluteFile();
887 File[] files = dir.listFiles();
888 for (int j = 0; j < files.length; j++) {
889 urlList.add(files[j].toURI().toURL());
890 }
891 } catch (Exception e) {
892 }
893 }
894 // TODO avoid security checking?
895 String classPath = System.getProperty("java.class.path",
896 File.pathSeparator);
897 st = fracture(classPath, File.pathSeparator);
898 l = st.length;
899 for (int i = 0; i < l; i++) {
900 try {
901 if(st[i].length() == 0) {
902 st[i] = ".";
903 }
904 urlList.add(new File(st[i]).toURI().toURL());
905 } catch (MalformedURLException e) {
906 assert false: e.toString();
907 }
908 }
909 instance = new SystemClassLoader(urlList
910 .toArray(new URL[urlList.size()]), null);
911 }
912
913 public static ClassLoader getInstance() {
914 return instance;
915 }
916 }
917 }