001: /*
002: * @(#)MIDletClassLoader.java 1.11 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027: /*
028: * @(#)MIDletClassLoader.java 1.5 03/07/09
029: *
030: * Class loader for midlets running on CDC/PP
031: *
032: * It loads from a single JAR file and deligates to other class loaders.
033: * It has a few of interesting properties:
034: * 1) it is careful, perhaps overly so, about not loading classes that
035: * are in system packages from the JAR file persumed to contain the MIDlet
036: * code.
037: * 2) it uses a MemberFilter to process classes for illegal field references.
038: * This is easiest to do after the constant pool is set up.
039: * 3) it remembers which classes have failed the above test and refuses to
040: * load them, even though the system thinks they're already loaded.
041: *
042: * It lets the underlying URLClassLoader do all the hard work.
043: *
044: */
045: package sun.misc;
046:
047: import java.net.URL;
048: import java.net.URLConnection;
049: import java.net.URLClassLoader;
050: import java.io.File;
051: import java.io.IOException;
052: import java.io.InputStream;
053: import java.util.HashSet;
054: import java.security.CodeSource;
055: import java.security.PermissionCollection;
056: import java.security.AccessController;
057: import java.security.AccessControlContext;
058: import java.security.PrivilegedAction;
059:
060: public class MIDletClassLoader extends URLClassLoader {
061:
062: URL myBase[];
063: String[] systemPkgs;
064: private MemberFilter memberChecker; /* to check for amputated members */
065: private PermissionCollection perms;
066: private HashSet badMidletClassnames = new HashSet();
067: private MIDPImplementationClassLoader implementationClassLoader;
068: private AccessControlContext ac = AccessController.getContext();
069: /*
070: * If the filter is disabled, all classes on the bootclasspath
071: * can be accessed from midlet.
072: */
073: private boolean enableFilter;
074: private ClassLoader auxClassLoader;
075:
076: public MIDletClassLoader(URL base[], String systemPkgs[],
077: PermissionCollection pc, MemberFilter mf,
078: MIDPImplementationClassLoader parent, boolean enableFilter,
079: ClassLoader auxClassLoader) {
080: super (base, parent);
081: myBase = base;
082: this .systemPkgs = systemPkgs;
083: memberChecker = mf;
084: perms = pc;
085: implementationClassLoader = parent;
086: this .enableFilter = enableFilter;
087: this .auxClassLoader = auxClassLoader;
088: }
089:
090: protected PermissionCollection getPermissions(CodeSource cs) {
091: URL srcLocation = cs.getLocation();
092: for (int i = 0; i < myBase.length; i++) {
093: if (srcLocation.equals(myBase[i])) {
094: return perms;
095: }
096: }
097: return super .getPermissions(cs);
098: }
099:
100: private Class loadFromUrl(String classname)
101: throws ClassNotFoundException {
102: // first ensure we like componentName.
103: // it should not have a systemPkg entry as a prefix!
104: // this is probably paranoid. There are probably other
105: // mechanisms to avoid this.
106: String forbidden[] = systemPkgs;
107: int fLength = forbidden.length;
108: for (int i = 0; i < fLength; i++) {
109: if (classname.startsWith(forbidden[i])) {
110: return null; // go look elsewhere.
111: }
112: }
113: Class newClass;
114: try {
115: newClass = super .findClass(classname); // call URLClassLoader
116: } catch (Exception e) {
117: /*DEBUG e.printStackTrace(); */
118: // didn't find it.
119: return null;
120: }
121: if (newClass == null)
122: return null;
123: try {
124: // memberChecker will throw an Error if it doesn't like
125: // the class.
126: if (enableFilter) {
127: memberChecker.checkMemberAccessValidity(newClass);
128: }
129: return newClass;
130: } catch (Error e) {
131: // If this happens, act as if we cannot find the class.
132: // remember this class, too. If the MIDlet catches the
133: // Exception and tries again, we don't want findLoadedClass()
134: // to return it!!
135: badMidletClassnames.add(classname);
136: throw new ClassNotFoundException(e.getMessage());
137: }
138: }
139:
140: public synchronized Class loadClass(String classname,
141: boolean resolve) throws ClassNotFoundException {
142: Class resultClass;
143: classname = classname.intern();
144: if (badMidletClassnames.contains(classname)) {
145: // the system thinks it successfully loaded this class.
146: // But the member checker does not think we should be able
147: // to use it. We threw an Exception before. Do it again.
148: throw new ClassNotFoundException(classname
149: .concat(" contains illegal member reference"));
150: }
151: resultClass = findLoadedClass(classname);
152: if (resultClass == null) {
153: resultClass = loadFromUrl(classname);
154: if (resultClass == null) {
155: resultClass = implementationClassLoader.loadClass(
156: classname, false, enableFilter);
157: }
158: }
159: /*
160: * If MIDletClassLoader and the parents failed to
161: * load the class, try the auxClassLoader.
162: */
163: if (resultClass == null && auxClassLoader != null) {
164: auxClassLoader.loadClass(classname);
165: }
166: if (resultClass == null)
167: throw new ClassNotFoundException(classname);
168: if (resolve)
169: resolveClass(resultClass);
170: return resultClass;
171: }
172:
173: public InputStream getResourceAsStream(String name) {
174: // prohibit reading .class as a resource
175: if (name.endsWith(".class")) {
176: return null; // not allowed!
177: }
178:
179: // The JAR reader cannot find the resource if the name starts with
180: // a slash. So we remove the leading slash if one exists.
181: if (name.startsWith("/") || name.startsWith(File.separator)) {
182: name = name.substring(1);
183: }
184:
185: final String n = name;
186: // do not delegate. We only use our own URLClassLoader.findResource to
187: // look in our own JAR file. That is always allowed.
188: // Nothing else is.
189: InputStream retval;
190: retval = (InputStream) AccessController.doPrivileged(
191: new PrivilegedAction() {
192: public Object run() {
193: URL url = findResource(n);
194: try {
195: return url != null ? url.openStream()
196: : null;
197: } catch (IOException e) {
198: return null;
199: }
200: }
201: }, ac);
202: return retval;
203: }
204:
205: }
|