001: /*
002: *
003: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License version
008: * 2 only, as published by the Free Software Foundation.
009: *
010: * This program is distributed in the hope that it will be useful, but
011: * WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * General Public License version 2 for more details (a copy is
014: * included at /legal/license.txt).
015: *
016: * You should have received a copy of the GNU General Public License
017: * version 2 along with this work; if not, write to the Free Software
018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022: * Clara, CA 95054 or visit www.sun.com if you need additional
023: * information or have any questions.
024: */
025:
026: /*
027: * @(#)MIDPConfig.java 1.11 06/10/30
028: * This class contains all the information necessary
029: * to configure a MemberFilter appropriate for MIDP2.0
030: * as well as some tables we need to configure the
031: * MIDPImplementationClassLoader
032: */
033: package sun.misc;
034:
035: import java.net.URL;
036: import java.security.PermissionCollection;
037: import java.security.Permissions;
038: import java.io.File;
039: import java.io.FileReader;
040: import java.io.InputStream;
041: import java.io.BufferedReader;
042: import java.util.Vector;
043: import java.net.MalformedURLException;
044:
045: public final class MIDPConfig {
046: /* The MIDP library classloader */
047: private static MIDPImplementationClassLoader midpImplCL;
048: /* The midlet classloader */
049: /*private static MIDletClassLoader midletCL;*/
050: /* The MemberFilter */
051: private static MemberFilter memberFilter;
052:
053: /* The default location of midp library zip */
054: private static String defaultMidpJarPath = System
055: .getProperty("java.home")
056: + File.separator
057: + "lib"
058: + File.separator
059: + "midpclasses.zip";
060:
061: public static String MIDPVersion = "2.0";
062: public static String CLDCVersion = "1.1";
063: /*
064: * The following data structures are for
065: * managing name visibility.
066: */
067: static String systemPackages[] = { "java.lang.", "java.io.",
068: "java.util.", "javax.microedition." };
069:
070: static {
071: // Create the member filter.
072: memberFilter = newMemberFilter();
073: }
074:
075: static String permittedSystemClasses[];
076:
077: // filled by reading a file.
078: // see getPermittedClasses() below
079:
080: /*
081: * Set up a MemberFilter using the classes and members
082: * given in the permittedMembers structures above.
083: * All MIDletClassLoaders will share the same MemberFilter
084: * since using it does not change its state.
085: */
086: public static MemberFilter newMemberFilter() {
087: try {
088: String filename = System.getProperty("java.home")
089: + File.separator + "lib" + File.separator
090: + "MIDPFilterConfig.txt";
091: MemberFilterConfig mfc = new MemberFilterConfig(filename);
092: MemberFilter mf;
093: // DEBUG System.out.println("Starting MemberFilter file parsing");
094: // DEBUG mfc.setVerbose(true);
095: mf = mfc.parseFile();
096: // DEBUG System.out.println("Done MemberFilter file parsing");
097: return mf;
098: } catch (java.io.IOException e) {
099: e.printStackTrace();
100: return null;
101: }
102: }
103:
104: private static String[] getPermittedClasses() {
105: if (permittedSystemClasses != null) {
106: return permittedSystemClasses;
107: }
108: BufferedReader infile;
109: Vector classnames;
110: int nnames = 0;
111: String filename = System.getProperty("java.home")
112: + File.separator + "lib" + File.separator
113: + "MIDPPermittedClasses.txt";
114: try {
115: infile = new BufferedReader(new FileReader(filename));
116: } catch (java.io.IOException e) {
117: /*DEBUG*/System.err.println("Could not open " + filename);
118: return null;
119: }
120: classnames = new Vector();
121: try {
122: while (true) {
123: String inline = infile.readLine();
124: if (inline == null)
125: break; // eof
126: if (inline.length() == 0)
127: continue; // blank line
128: if (inline.charAt(0) == '#')
129: continue; // comment
130: classnames.add(inline);
131: nnames += 1;
132: }
133: infile.close();
134: } catch (java.io.IOException e) {
135: /*DEBUG*/System.err.println("Exception while reading "
136: + filename);
137: return null;
138: }
139: permittedSystemClasses = new String[nnames];
140: classnames.copyInto(permittedSystemClasses);
141: return permittedSystemClasses;
142: }
143:
144: /*
145: * Set up the MIDPImplementationClassLoader.
146: * All MIDlets will share the same MIDPImplementationClassLoader,
147: * and thus the same class instances. This is required if we want
148: * to be able to coordinate their resource use.
149: * (Assuming that the implementation don't have any static fields
150: * that would make this sharing a bad idea!)
151: *
152: * We trust these classes, so grant them all permissions.
153: */
154: /* NOTE: this should be removed once the MIDP code is fixed to
155: * use the newMIDPImplementationClassLoader(URL[]) API.
156: */
157: public static MIDPImplementationClassLoader newMIDPImplementationClassLoader(
158: String midpJarNames[]) {
159: /* The MIDPImplementationClassLoader already exist. Throw an
160: * exception.
161: */
162: if (midpImplCL != null) {
163: throw new InternalError(
164: "The MIDPImplementationClassLoader is already created");
165: }
166:
167: String permittedClasses[];
168: PermissionCollection perms = new Permissions();
169: Vector urls = new Vector();
170: for (int i = 0; i < midpJarNames.length; i++) {
171: try {
172: File file = new File(midpJarNames[i]);
173: if (file.exists()) {
174: urls.add(file.toURL());
175: }
176: } catch (NullPointerException e) {
177: } catch (java.io.IOException e) {
178: e.printStackTrace();
179: }
180: }
181:
182: URL[] midpBase = (URL[]) urls.toArray(new URL[0]);
183:
184: if (midpBase == null || midpBase.length == 0) {
185: /* Either the parameter was bad or didn't get passed in. Use default. */
186: midpBase = new URL[1];
187: try {
188: midpBase[0] = new URL("file://"
189: .concat(defaultMidpJarPath));
190: } catch (java.io.IOException e) {
191: // DEBUG System.err.println("initMidpImplementation URL Creation:");
192: e.printStackTrace();
193: // END DEBUG
194: return null;
195: }
196: }
197:
198: perms.add(new java.security.AllPermission());
199: //DEBUG System.out.println("Constructing MIDPImplementationClassLoader with permissions "+perms);
200: permittedClasses = getPermittedClasses();
201: if (permittedClasses == null) {
202: // there was some problem in reading the file
203: return null;
204: }
205:
206: midpImplCL = new MIDPImplementationClassLoader(midpBase,
207: permittedClasses, perms, null);
208: return midpImplCL;
209:
210: }
211:
212: public static MIDPImplementationClassLoader getMIDPImplementationClassLoader() {
213: return midpImplCL;
214: }
215:
216: public static MIDPImplementationClassLoader newMIDPImplementationClassLoader(
217: File files[]) {
218: /* The MIDPImplementationClassLoader already exist. Throw an
219: * exception.
220: */
221: if (midpImplCL != null) {
222: throw new InternalError(
223: "The MIDPImplementationClassLoader is already created");
224: }
225:
226: String permittedClasses[];
227: PermissionCollection perms = new Permissions();
228:
229: URL urls[] = new URL[files.length];
230: for (int i = 0; i < files.length; i++) {
231: try {
232: urls[i] = files[i].toURL();
233: } catch (MalformedURLException e) {
234: e.printStackTrace();
235: urls = null;
236: break;
237: }
238: }
239: if (urls == null || urls.length == 0) {
240: /* Either the parameter was bad or didn't get passed in. Use default. */
241: urls = new URL[1];
242: try {
243: urls[0] = new URL("file://".concat(defaultMidpJarPath));
244: } catch (java.io.IOException e) {
245: // DEBUG System.err.println("initMidpImplementation URL Creation:");
246: e.printStackTrace();
247: // END DEBUG
248: return null;
249: }
250: }
251:
252: perms.add(new java.security.AllPermission());
253: //DEBUG System.out.println(
254: // "Constructing MIDPImplementationClassLoader with permissions "+perms);
255: permittedClasses = getPermittedClasses();
256: if (permittedClasses == null) {
257: // there was some problem in reading the file
258: return null;
259: }
260: midpImplCL = new MIDPImplementationClassLoader(urls,
261: permittedClasses, perms, null);
262: return midpImplCL;
263: }
264:
265: /*
266: * Set up the permissions that will be granted to MIDlet code proper.
267: * Currently this is very little: only the ability to modify the properties
268: * of a Thread. And this is very limited by API hiding so is not very dangerous.
269: * We absolutely do not give them vmExit, which is explicitly prohibited.
270: * This set of permissions is read-only and shared by all MIDletClassLoaders.
271: *
272: * Property access cannot be dealt with using Java permissions, as we
273: * want to make properties disappear, and permissions will throw an Exception
274: * to prohibit seeing the property.
275: *
276: * This depends on being run in the following environment:
277: * security enabled, but all permissions granted to main program.
278: * This is achieved but putting -Djava.security.manager on
279: * the command line, and having my own .java.policy file
280: * that looks like this:
281: * grant codeBase "file:*" {
282: * permission java.security.AllPermission;
283: * };
284: */
285:
286: static PermissionCollection newMidletPermissions() {
287: PermissionCollection mp = new Permissions();
288: mp.add(new java.lang.RuntimePermission("modifyThread"));
289: mp.add(new java.util.PropertyPermission("*", "read"));
290: mp.setReadOnly();
291: return mp;
292: }
293:
294: static PermissionCollection midletPermissions = newMidletPermissions();
295:
296: /*
297: * Set up a new MIDletClassLoader
298: * There should probably be one of these per MIDlet suite.
299: * This would allow sharing between suite members, including data.
300: */
301:
302: static String[] split(String path) {
303: int nComponents = 1;
304: char separator = System.getProperty("path.separator", ":")
305: .charAt(0);
306: String components[];
307: int length = path.length();
308: int start;
309: int componentIndex;
310: for (int i = 0; i < length; i++) {
311: if (path.charAt(i) == separator)
312: nComponents += 1;
313: }
314: components = new String[nComponents];
315: start = 0;
316: componentIndex = 0;
317: /* could optimize here for the common case of nComponents == 1 */
318: for (int i = 0; i < length; i++) {
319: if (path.charAt(i) == separator) {
320: components[componentIndex] = path.substring(start, i);
321: componentIndex += 1;
322: start = i + 1;
323: }
324: }
325: /* and the last components is delimited by end of String */
326: components[componentIndex] = path.substring(start, length);
327:
328: return components;
329:
330: }
331:
332: /*
333: * This version allows the caller to specify a set of permissions.
334: * This is less useful than the usual version, which grants the
335: * permissions we plan on granting to MIDlets.
336: *
337: * The 'enableFilter' argument specifies that if the API hiding
338: * filter is being enabled. If the filter is enabled, midlet
339: * can only access CLDC/MIDP classes. If the filter is disabled,
340: * midlet can access all classes on the bootclasspath, including
341: * all the CDC classes.
342: *
343: * The 'auxClassLoader' is a helper classloader used when the
344: * MIDletClassLoader and its parents fail to load the requested
345: * class.
346: */
347: private static MIDletClassLoader newMIDletClassLoader(
348: String midpPath[], MemberFilter mf,
349: PermissionCollection perms,
350: MIDPImplementationClassLoader implClassLdr,
351: boolean enableFilter, ClassLoader auxClassLoader) {
352: if (midpImplCL == null) {
353: throw new InternalError(
354: "Need to create the parent MIDPImplementationClassLoader first");
355: }
356:
357: URL midJarURL[];
358: int nComponents = midpPath.length;
359:
360: midJarURL = new URL[nComponents];
361: try {
362: for (int i = 0; i < nComponents; i++) {
363: midJarURL[i] = new URL("file://".concat(midpPath[i]));
364: }
365: } catch (Exception e) {
366: System.err.println("URL Creation:");
367: e.printStackTrace();
368: return null;
369: }
370: //DEBUG System.out.println("Constructing MIDletClassLoader with permissions "+perms);
371: MIDletClassLoader midletCL = new MIDletClassLoader(midJarURL,
372: systemPackages, perms, mf, implClassLdr, enableFilter,
373: auxClassLoader);
374:
375: return midletCL;
376: }
377:
378: /*
379: * This version allows the caller to specify a set of permissions.
380: * The parent classloader is the MIDPImplementationClassLoader.
381: * The API hiding filter is enabled.
382: */
383: public static MIDletClassLoader newMIDletClassLoader(
384: String midpPath[], PermissionCollection perms) {
385: return newMIDletClassLoader(midpPath, memberFilter, perms,
386: midpImplCL, true, null);
387: }
388:
389: /*
390: * Use the default midlet permission collection. The parent classloader
391: * is the MIDPImplementationClassLoader. The API hiding filter is
392: * enabled.
393: */
394: public static MIDletClassLoader newMIDletClassLoader(
395: String midpPath[]) {
396: return newMIDletClassLoader(midpPath, memberFilter,
397: midletPermissions, midpImplCL, true, null);
398: }
399:
400: /*
401: * The 'enableFilter' argument specifies that if the API hiding
402: * filter is being enabled. If the filter is enabled, midlet
403: * can only access CLDC/MIDP classes. If the filter is disabled,
404: * midlet can access all classes on the bootclasspath, including
405: * all the CDC classes.
406: *
407: * The 'auxClassLoader' is a helper classloader used when the
408: * MIDletClassLoader and its parents fail to load the requested
409: * class.
410: */
411: public static MIDletClassLoader newMIDletClassLoader(
412: String midpPath[], boolean enableFilter,
413: ClassLoader auxClassLoader) {
414: return newMIDletClassLoader(midpPath, memberFilter,
415: midletPermissions, midpImplCL, enableFilter,
416: auxClassLoader);
417: }
418:
419: /*
420: * Get the MIDletClassLoader instance that loads the caller
421: * midlet class.
422: */
423: public static MIDletClassLoader getMIDletClassLoader() {
424: int i = 1; /* skip the direct caller, who must be system code */
425: ClassLoader loader = null;
426: Class cl = CVM.getCallerClass(i);
427:
428: while (cl != null) {
429: loader = cl.getClassLoader();
430: if (loader instanceof MIDletClassLoader) {
431: return (MIDletClassLoader) loader;
432: }
433: cl = CVM.getCallerClass(++i);
434: }
435: return null;
436: }
437:
438: /*
439: * A utility method used to load resources using the caller's
440: * classloaders. This is useful when application and system
441: * code are loaded by different classloaders.
442: */
443: public static InputStream getResourceAsStream(String name) {
444: int i = 1; /* skip tha caller, which must be system code */
445: InputStream is = null;
446: ClassLoader lastFailedLoader = null;
447:
448: /* This is a bit slow since we need to walk up the stack.
449: * Because we don't know which classloader to load the resource,
450: * so we have to do it the hard way. */
451: while (is == null) {
452: Class cl = sun.misc.CVM.getCallerClass(i);
453: if (cl == null) { /* reach the top of the stack */
454: break;
455: }
456:
457: ClassLoader loader = cl.getClassLoader();
458: if (i == 1 || loader != lastFailedLoader) {
459: is = cl.getResourceAsStream(name);
460: if (is != null) {
461: break;
462: } else {
463: lastFailedLoader = loader;
464: }
465: }
466:
467: i++; /* the next caller */
468: }
469: return is;
470: }
471: }
|