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/*
18 * Copyright (C) 2008 The Android Open Source Project
19 *
20 * Licensed under the Apache License, Version 2.0 (the "License");
21 * you may not use this file except in compliance with the License.
22 * You may obtain a copy of the License at
23 *
24 * http://www.apache.org/licenses/LICENSE-2.0
25 *
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS,
28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 * See the License for the specific language governing permissions and
30 * limitations under the License.
31 */
32
33package java.lang;
34
35import dalvik.system.PathClassLoader;
36import dalvik.system.VMStack;
37import java.io.IOException;
38import java.io.InputStream;
39import java.net.URL;
40import java.nio.ByteBuffer;
41import java.security.ProtectionDomain;
42import java.util.Collection;
43import java.util.Collections;
44import java.util.Enumeration;
45import java.util.HashMap;
46import java.util.Map;
47
48/**
49 * Loads classes and resources from a repository. One or more class loaders are
50 * installed at runtime. These are consulted whenever the runtime system needs a
51 * specific class that is not yet available in-memory. Typically, class loaders
52 * are grouped into a tree where child class loaders delegate all requests to
53 * parent class loaders. Only if the parent class loader cannot satisfy the
54 * request, the child class loader itself tries to handle it.
55 * <p>
56 * {@code ClassLoader} is an abstract class that implements the common
57 * infrastructure required by all class loaders. Android provides several
58 * concrete implementations of the class, with
59 * {@link dalvik.system.PathClassLoader} being the one typically used. Other
60 * applications may implement subclasses of {@code ClassLoader} to provide
61 * special ways for loading classes.
62 * </p>
63 * @see Class
64 */
65public abstract class ClassLoader {
66
67    /**
68     * The 'System' ClassLoader - the one that is responsible for loading
69     * classes from the classpath. It is not equal to the bootstrap class loader -
70     * that one handles the built-in classes.
71     *
72     * Because of a potential class initialization race between ClassLoader and
73     * java.lang.System, reproducible when using JDWP with "suspend=y", we defer
74     * creation of the system class loader until first use. We use a static
75     * inner class to get synchronization at init time without having to sync on
76     * every access.
77     *
78     * @see #getSystemClassLoader()
79     */
80    static private class SystemClassLoader {
81        public static ClassLoader loader = ClassLoader.createSystemClassLoader();
82    }
83
84    /**
85     * The parent ClassLoader.
86     */
87    private ClassLoader parent;
88
89    /**
90     * The packages known to the class loader.
91     */
92    private Map<String, Package> packages = new HashMap<String, Package>();
93
94    /**
95     * Create the system class loader. Note this is NOT the bootstrap class
96     * loader (which is managed by the VM). We use a null value for the parent
97     * to indicate that the bootstrap loader is our parent.
98     */
99    private static ClassLoader createSystemClassLoader() {
100        String classPath = System.getProperty("java.class.path", ".");
101
102        // String[] paths = classPath.split(":");
103        // URL[] urls = new URL[paths.length];
104        // for (int i = 0; i < paths.length; i++) {
105        // try {
106        // urls[i] = new URL("file://" + paths[i]);
107        // }
108        // catch (Exception ex) {
109        // ex.printStackTrace();
110        // }
111        // }
112        //
113        // return new java.net.URLClassLoader(urls, null);
114
115        // TODO Make this a java.net.URLClassLoader once we have those?
116        return new PathClassLoader(classPath, BootClassLoader.getInstance());
117    }
118
119    /**
120     * Returns the system class loader. This is the parent for new
121     * {@code ClassLoader} instances and is typically the class loader used to
122     * start the application.
123     */
124    public static ClassLoader getSystemClassLoader() {
125        return SystemClassLoader.loader;
126    }
127
128    /**
129     * Finds the URL of the resource with the specified name. The system class
130     * loader's resource lookup algorithm is used to find the resource.
131     *
132     * @return the {@code URL} object for the requested resource or {@code null}
133     *         if the resource can not be found.
134     * @param resName
135     *            the name of the resource to find.
136     * @see Class#getResource
137     */
138    public static URL getSystemResource(String resName) {
139        return SystemClassLoader.loader.getResource(resName);
140    }
141
142    /**
143     * Returns an enumeration of URLs for the resource with the specified name.
144     * The system class loader's resource lookup algorithm is used to find the
145     * resource.
146     *
147     * @return an enumeration of {@code URL} objects containing the requested
148     *         resources.
149     * @param resName
150     *            the name of the resource to find.
151     * @throws IOException
152     *             if an I/O error occurs.
153     */
154    public static Enumeration<URL> getSystemResources(String resName) throws IOException {
155        return SystemClassLoader.loader.getResources(resName);
156    }
157
158    /**
159     * Returns a stream for the resource with the specified name. The system
160     * class loader's resource lookup algorithm is used to find the resource.
161     * Basically, the contents of the java.class.path are searched in order,
162     * looking for a path which matches the specified resource.
163     *
164     * @return a stream for the resource or {@code null}.
165     * @param resName
166     *            the name of the resource to find.
167     * @see Class#getResourceAsStream
168     */
169    public static InputStream getSystemResourceAsStream(String resName) {
170        return SystemClassLoader.loader.getResourceAsStream(resName);
171    }
172
173    /**
174     * Constructs a new instance of this class with the system class loader as
175     * its parent.
176     */
177    protected ClassLoader() {
178        this(getSystemClassLoader(), false);
179    }
180
181    /**
182     * Constructs a new instance of this class with the specified class loader
183     * as its parent.
184     *
185     * @param parentLoader
186     *            The {@code ClassLoader} to use as the new class loader's
187     *            parent.
188     */
189    protected ClassLoader(ClassLoader parentLoader) {
190        this(parentLoader, false);
191    }
192
193    /*
194     * constructor for the BootClassLoader which needs parent to be null.
195     */
196    ClassLoader(ClassLoader parentLoader, boolean nullAllowed) {
197        if (parentLoader == null && !nullAllowed) {
198            throw new NullPointerException("parentLoader == null && !nullAllowed");
199        }
200        parent = parentLoader;
201    }
202
203    /**
204     * Constructs a new class from an array of bytes containing a class
205     * definition in class file format.
206     *
207     * @param classRep
208     *            the memory image of a class file.
209     * @param offset
210     *            the offset into {@code classRep}.
211     * @param length
212     *            the length of the class file.
213     * @return the {@code Class} object created from the specified subset of
214     *         data in {@code classRep}.
215     * @throws ClassFormatError
216     *             if {@code classRep} does not contain a valid class.
217     * @throws IndexOutOfBoundsException
218     *             if {@code offset < 0}, {@code length < 0} or if
219     *             {@code offset + length} is greater than the length of
220     *             {@code classRep}.
221     * @deprecated Use {@link #defineClass(String, byte[], int, int)} instead.
222     */
223    @Deprecated
224    protected final Class<?> defineClass(byte[] classRep, int offset, int length)
225            throws ClassFormatError {
226        throw new UnsupportedOperationException("can't load this type of class file");
227    }
228
229    /**
230     * Constructs a new class from an array of bytes containing a class
231     * definition in class file format.
232     *
233     * @param className
234     *            the expected name of the new class, may be {@code null} if not
235     *            known.
236     * @param classRep
237     *            the memory image of a class file.
238     * @param offset
239     *            the offset into {@code classRep}.
240     * @param length
241     *            the length of the class file.
242     * @return the {@code Class} object created from the specified subset of
243     *         data in {@code classRep}.
244     * @throws ClassFormatError
245     *             if {@code classRep} does not contain a valid class.
246     * @throws IndexOutOfBoundsException
247     *             if {@code offset < 0}, {@code length < 0} or if
248     *             {@code offset + length} is greater than the length of
249     *             {@code classRep}.
250     */
251    protected final Class<?> defineClass(String className, byte[] classRep, int offset, int length)
252            throws ClassFormatError {
253        throw new UnsupportedOperationException("can't load this type of class file");
254    }
255
256    /**
257     * Constructs a new class from an array of bytes containing a class
258     * definition in class file format and assigns the specified protection
259     * domain to the new class. If the provided protection domain is
260     * {@code null} then a default protection domain is assigned to the class.
261     *
262     * @param className
263     *            the expected name of the new class, may be {@code null} if not
264     *            known.
265     * @param classRep
266     *            the memory image of a class file.
267     * @param offset
268     *            the offset into {@code classRep}.
269     * @param length
270     *            the length of the class file.
271     * @param protectionDomain
272     *            the protection domain to assign to the loaded class, may be
273     *            {@code null}.
274     * @return the {@code Class} object created from the specified subset of
275     *         data in {@code classRep}.
276     * @throws ClassFormatError
277     *             if {@code classRep} does not contain a valid class.
278     * @throws IndexOutOfBoundsException
279     *             if {@code offset < 0}, {@code length < 0} or if
280     *             {@code offset + length} is greater than the length of
281     *             {@code classRep}.
282     * @throws NoClassDefFoundError
283     *             if {@code className} is not equal to the name of the class
284     *             contained in {@code classRep}.
285     */
286    protected final Class<?> defineClass(String className, byte[] classRep, int offset, int length,
287            ProtectionDomain protectionDomain) throws java.lang.ClassFormatError {
288        throw new UnsupportedOperationException("can't load this type of class file");
289    }
290
291    /**
292     * Defines a new class with the specified name, byte code from the byte
293     * buffer and the optional protection domain. If the provided protection
294     * domain is {@code null} then a default protection domain is assigned to
295     * the class.
296     *
297     * @param name
298     *            the expected name of the new class, may be {@code null} if not
299     *            known.
300     * @param b
301     *            the byte buffer containing the byte code of the new class.
302     * @param protectionDomain
303     *            the protection domain to assign to the loaded class, may be
304     *            {@code null}.
305     * @return the {@code Class} object created from the data in {@code b}.
306     * @throws ClassFormatError
307     *             if {@code b} does not contain a valid class.
308     * @throws NoClassDefFoundError
309     *             if {@code className} is not equal to the name of the class
310     *             contained in {@code b}.
311     */
312    protected final Class<?> defineClass(String name, ByteBuffer b,
313            ProtectionDomain protectionDomain) throws ClassFormatError {
314
315        byte[] temp = new byte[b.remaining()];
316        b.get(temp);
317        return defineClass(name, temp, 0, temp.length, protectionDomain);
318    }
319
320    /**
321     * Overridden by subclasses, throws a {@code ClassNotFoundException} by
322     * default. This method is called by {@code loadClass} after the parent
323     * {@code ClassLoader} has failed to find a loaded class of the same name.
324     *
325     * @param className
326     *            the name of the class to look for.
327     * @return the {@code Class} object that is found.
328     * @throws ClassNotFoundException
329     *             if the class cannot be found.
330     */
331    protected Class<?> findClass(String className) throws ClassNotFoundException {
332        throw new ClassNotFoundException(className);
333    }
334
335    /**
336     * Returns the class with the specified name if it has already been loaded
337     * by the VM or {@code null} if it has not yet been loaded.
338     *
339     * @param className
340     *            the name of the class to look for.
341     * @return the {@code Class} object or {@code null} if the requested class
342     *         has not been loaded.
343     */
344    protected final Class<?> findLoadedClass(String className) {
345        ClassLoader loader;
346        if (this == BootClassLoader.getInstance())
347            loader = null;
348        else
349            loader = this;
350        return VMClassLoader.findLoadedClass(loader, className);
351    }
352
353    /**
354     * Finds the class with the specified name, loading it using the system
355     * class loader if necessary.
356     *
357     * @param className
358     *            the name of the class to look for.
359     * @return the {@code Class} object with the requested {@code className}.
360     * @throws ClassNotFoundException
361     *             if the class can not be found.
362     */
363    protected final Class<?> findSystemClass(String className) throws ClassNotFoundException {
364        return Class.forName(className, false, getSystemClassLoader());
365    }
366
367    /**
368     * Returns this class loader's parent.
369     *
370     * @return this class loader's parent or {@code null}.
371     */
372    public final ClassLoader getParent() {
373        return parent;
374    }
375
376    /**
377     * Returns the URL of the resource with the specified name. This
378     * implementation first tries to use the parent class loader to find the
379     * resource; if this fails then {@link #findResource(String)} is called to
380     * find the requested resource.
381     *
382     * @param resName
383     *            the name of the resource to find.
384     * @return the {@code URL} object for the requested resource or {@code null}
385     *         if the resource can not be found
386     * @see Class#getResource
387     */
388    public URL getResource(String resName) {
389        URL resource = parent.getResource(resName);
390        if (resource == null) {
391            resource = findResource(resName);
392        }
393        return resource;
394    }
395
396    /**
397     * Returns an enumeration of URLs for the resource with the specified name.
398     * This implementation first uses this class loader's parent to find the
399     * resource, then it calls {@link #findResources(String)} to get additional
400     * URLs. The returned enumeration contains the {@code URL} objects of both
401     * find operations.
402     *
403     * @return an enumeration of {@code URL} objects for the requested resource.
404     * @param resName
405     *            the name of the resource to find.
406     * @throws IOException
407     *             if an I/O error occurs.
408     */
409    @SuppressWarnings("unchecked")
410    public Enumeration<URL> getResources(String resName) throws IOException {
411
412        Enumeration first = parent.getResources(resName);
413        Enumeration second = findResources(resName);
414
415        return new TwoEnumerationsInOne(first, second);
416    }
417
418    /**
419     * Returns a stream for the resource with the specified name. See
420     * {@link #getResource(String)} for a description of the lookup algorithm
421     * used to find the resource.
422     *
423     * @return a stream for the resource or {@code null} if the resource can not be found
424     * @param resName
425     *            the name of the resource to find.
426     * @see Class#getResourceAsStream
427     */
428    public InputStream getResourceAsStream(String resName) {
429        try {
430            URL url = getResource(resName);
431            if (url != null) {
432                return url.openStream();
433            }
434        } catch (IOException ex) {
435            // Don't want to see the exception.
436        }
437
438        return null;
439    }
440
441    /**
442     * Loads the class with the specified name. Invoking this method is
443     * equivalent to calling {@code loadClass(className, false)}.
444     * <p>
445     * <strong>Note:</strong> In the Android reference implementation, the
446     * second parameter of {@link #loadClass(String, boolean)} is ignored
447     * anyway.
448     * </p>
449     *
450     * @return the {@code Class} object.
451     * @param className
452     *            the name of the class to look for.
453     * @throws ClassNotFoundException
454     *             if the class can not be found.
455     */
456    public Class<?> loadClass(String className) throws ClassNotFoundException {
457        return loadClass(className, false);
458    }
459
460    /**
461     * Loads the class with the specified name, optionally linking it after
462     * loading. The following steps are performed:
463     * <ol>
464     * <li> Call {@link #findLoadedClass(String)} to determine if the requested
465     * class has already been loaded.</li>
466     * <li>If the class has not yet been loaded: Invoke this method on the
467     * parent class loader.</li>
468     * <li>If the class has still not been loaded: Call
469     * {@link #findClass(String)} to find the class.</li>
470     * </ol>
471     * <p>
472     * <strong>Note:</strong> In the Android reference implementation, the
473     * {@code resolve} parameter is ignored; classes are never linked.
474     * </p>
475     *
476     * @return the {@code Class} object.
477     * @param className
478     *            the name of the class to look for.
479     * @param resolve
480     *            Indicates if the class should be resolved after loading. This
481     *            parameter is ignored on the Android reference implementation;
482     *            classes are not resolved.
483     * @throws ClassNotFoundException
484     *             if the class can not be found.
485     */
486    protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
487        Class<?> clazz = findLoadedClass(className);
488
489        if (clazz == null) {
490            try {
491                clazz = parent.loadClass(className, false);
492            } catch (ClassNotFoundException e) {
493                // Don't want to see this.
494            }
495
496            if (clazz == null) {
497                clazz = findClass(className);
498            }
499        }
500
501        return clazz;
502    }
503
504    /**
505     * Forces a class to be linked (initialized). If the class has already been
506     * linked this operation has no effect.
507     * <p>
508     * <strong>Note:</strong> In the Android reference implementation, this
509     * method has no effect.
510     * </p>
511     *
512     * @param clazz
513     *            the class to link.
514     */
515    protected final void resolveClass(Class<?> clazz) {
516        // no-op, doesn't make sense on android.
517    }
518
519    /**
520     * Finds the URL of the resource with the specified name. This
521     * implementation just returns {@code null}; it should be overridden in
522     * subclasses.
523     *
524     * @param resName
525     *            the name of the resource to find.
526     * @return the {@code URL} object for the requested resource.
527     */
528    protected URL findResource(String resName) {
529        return null;
530    }
531
532    /**
533     * Finds an enumeration of URLs for the resource with the specified name.
534     * This implementation just returns an empty {@code Enumeration}; it should
535     * be overridden in subclasses.
536     *
537     * @param resName
538     *            the name of the resource to find.
539     * @return an enumeration of {@code URL} objects for the requested resource.
540     * @throws IOException
541     *             if an I/O error occurs.
542     */
543    @SuppressWarnings( {
544            "unchecked", "unused"
545    })
546    protected Enumeration<URL> findResources(String resName) throws IOException {
547        return Collections.emptyEnumeration();
548    }
549
550    /**
551     * Returns the absolute path of the native library with the specified name,
552     * or {@code null}. If this method returns {@code null} then the virtual
553     * machine searches the directories specified by the system property
554     * "java.library.path".
555     * <p>
556     * This implementation always returns {@code null}.
557     * </p>
558     *
559     * @param libName
560     *            the name of the library to find.
561     * @return the absolute path of the library.
562     */
563    protected String findLibrary(String libName) {
564        return null;
565    }
566
567    /**
568     * Returns the package with the specified name. Package information is
569     * searched in this class loader.
570     *
571     * @param name
572     *            the name of the package to find.
573     * @return the package with the requested name; {@code null} if the package
574     *         can not be found.
575     */
576    protected Package getPackage(String name) {
577        synchronized (packages) {
578            return packages.get(name);
579        }
580    }
581
582    /**
583     * Returns all the packages known to this class loader.
584     *
585     * @return an array with all packages known to this class loader.
586     */
587    protected Package[] getPackages() {
588        synchronized (packages) {
589            Collection<Package> col = packages.values();
590            Package[] result = new Package[col.size()];
591            col.toArray(result);
592            return result;
593        }
594    }
595
596    /**
597     * Defines and returns a new {@code Package} using the specified
598     * information. If {@code sealBase} is {@code null}, the package is left
599     * unsealed. Otherwise, the package is sealed using this URL.
600     *
601     * @param name
602     *            the name of the package.
603     * @param specTitle
604     *            the title of the specification.
605     * @param specVersion
606     *            the version of the specification.
607     * @param specVendor
608     *            the vendor of the specification.
609     * @param implTitle
610     *            the implementation title.
611     * @param implVersion
612     *            the implementation version.
613     * @param implVendor
614     *            the specification vendor.
615     * @param sealBase
616     *            the URL used to seal this package or {@code null} to leave the
617     *            package unsealed.
618     * @return the {@code Package} object that has been created.
619     * @throws IllegalArgumentException
620     *             if a package with the specified name already exists.
621     */
622    protected Package definePackage(String name, String specTitle, String specVersion,
623            String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase)
624            throws IllegalArgumentException {
625
626        synchronized (packages) {
627            if (packages.containsKey(name)) {
628                throw new IllegalArgumentException("Package " + name + " already defined");
629            }
630
631            Package newPackage = new Package(name, specTitle, specVersion, specVendor, implTitle,
632                    implVersion, implVendor, sealBase);
633
634            packages.put(name, newPackage);
635
636            return newPackage;
637        }
638    }
639
640    /**
641     * Sets the signers of the specified class. This implementation does
642     * nothing.
643     *
644     * @param c
645     *            the {@code Class} object for which to set the signers.
646     * @param signers
647     *            the signers for {@code c}.
648     */
649    protected final void setSigners(Class<?> c, Object[] signers) {
650    }
651
652    /**
653     * Sets the assertion status of the class with the specified name.
654     * <p>
655     * <strong>Note: </strong>This method does nothing in the Android reference
656     * implementation.
657     * </p>
658     *
659     * @param cname
660     *            the name of the class for which to set the assertion status.
661     * @param enable
662     *            the new assertion status.
663     */
664    public void setClassAssertionStatus(String cname, boolean enable) {
665    }
666
667    /**
668     * Sets the assertion status of the package with the specified name.
669     * <p>
670     * <strong>Note: </strong>This method does nothing in the Android reference
671     * implementation.
672     * </p>
673     *
674     * @param pname
675     *            the name of the package for which to set the assertion status.
676     * @param enable
677     *            the new assertion status.
678     */
679    public void setPackageAssertionStatus(String pname, boolean enable) {
680    }
681
682    /**
683     * Sets the default assertion status for this class loader.
684     * <p>
685     * <strong>Note: </strong>This method does nothing in the Android reference
686     * implementation.
687     * </p>
688     *
689     * @param enable
690     *            the new assertion status.
691     */
692    public void setDefaultAssertionStatus(boolean enable) {
693    }
694
695    /**
696     * Sets the default assertion status for this class loader to {@code false}
697     * and removes any package default and class assertion status settings.
698     * <p>
699     * <strong>Note:</strong> This method does nothing in the Android reference
700     * implementation.
701     * </p>
702     */
703    public void clearAssertionStatus() {
704    }
705}
706
707/*
708 * Provides a helper class that combines two existing URL enumerations into one.
709 * It is required for the getResources() methods. Items are fetched from the
710 * first enumeration until it's empty, then from the second one.
711 */
712class TwoEnumerationsInOne implements Enumeration<URL> {
713
714    private Enumeration<URL> first;
715
716    private Enumeration<URL> second;
717
718    public TwoEnumerationsInOne(Enumeration<URL> first, Enumeration<URL> second) {
719        this.first = first;
720        this.second = second;
721    }
722
723    public boolean hasMoreElements() {
724        return first.hasMoreElements() || second.hasMoreElements();
725    }
726
727    public URL nextElement() {
728        if (first.hasMoreElements()) {
729            return first.nextElement();
730        } else {
731            return second.nextElement();
732        }
733    }
734
735}
736
737/**
738 * Provides an explicit representation of the boot class loader. It sits at the
739 * head of the class loader chain and delegates requests to the VM's internal
740 * class loading mechanism.
741 */
742class BootClassLoader extends ClassLoader {
743
744    private static BootClassLoader instance;
745
746    @FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED")
747    public static synchronized BootClassLoader getInstance() {
748        if (instance == null) {
749            instance = new BootClassLoader();
750        }
751
752        return instance;
753    }
754
755    public BootClassLoader() {
756        super(null, true);
757    }
758
759    @Override
760    protected Class<?> findClass(String name) throws ClassNotFoundException {
761        return VMClassLoader.loadClass(name, false);
762    }
763
764    @Override
765    protected URL findResource(String name) {
766        return VMClassLoader.getResource(name);
767    }
768
769    @SuppressWarnings("unused")
770    @Override
771    protected Enumeration<URL> findResources(String resName) throws IOException {
772        return Collections.enumeration(VMClassLoader.getResources(resName));
773    }
774
775    /**
776     * Returns package information for the given package. Unfortunately, the
777     * Android BootClassLoader doesn't really have this information, and as a
778     * non-secure ClassLoader, it isn't even required to, according to the spec.
779     * Yet, we want to provide it, in order to make all those hopeful callers of
780     * {@code myClass.getPackage().getName()} happy. Thus we construct a Package
781     * object the first time it is being requested and fill most of the fields
782     * with dummy values. The Package object is then put into the ClassLoader's
783     * Package cache, so we see the same one next time. We don't create Package
784     * objects for null arguments or for the default package.
785     * <p>
786     * There a limited chance that we end up with multiple Package objects
787     * representing the same package: It can happen when when a package is
788     * scattered across different JAR files being loaded by different
789     * ClassLoaders. Rather unlikely, and given that this whole thing is more or
790     * less a workaround, probably not worth the effort.
791     */
792    @Override
793    protected Package getPackage(String name) {
794        if (name != null && !name.isEmpty()) {
795            synchronized (this) {
796                Package pack = super.getPackage(name);
797
798                if (pack == null) {
799                    pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0",
800                            "Unknown", null);
801                }
802
803                return pack;
804            }
805        }
806
807        return null;
808    }
809
810    @Override
811    public URL getResource(String resName) {
812        return findResource(resName);
813    }
814
815    @Override
816    protected Class<?> loadClass(String className, boolean resolve)
817           throws ClassNotFoundException {
818        Class<?> clazz = findLoadedClass(className);
819
820        if (clazz == null) {
821            clazz = findClass(className);
822        }
823
824        return clazz;
825    }
826
827    @Override
828    public Enumeration<URL> getResources(String resName) throws IOException {
829        return findResources(resName);
830    }
831}
832
833/**
834 * TODO Open issues - Missing / empty methods - Signer stuff - Protection
835 * domains - Assertions
836 */
837