001: /*
002: *
003: *
004: * Copyright 1990-2007 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: package com.sun.midp.midletsuite;
028:
029: import java.io.IOException;
030:
031: import com.sun.midp.security.SecurityToken;
032: import com.sun.midp.security.Permissions;
033:
034: import com.sun.midp.midlet.MIDletSuite;
035: import com.sun.midp.midlet.MIDletStateHandler;
036:
037: import com.sun.midp.content.CHManager;
038:
039: import com.sun.midp.util.Properties;
040:
041: import com.sun.midp.configurator.Constants;
042:
043: import com.sun.midp.rms.RecordStoreImpl;
044:
045: import com.sun.midp.log.Logging;
046: import com.sun.midp.log.LogChannels;
047: import com.sun.midp.installer.JarReader;
048:
049: /**
050: * This class manages the persistent data for MIDlet suites.
051: * <P>
052: * Each installed package is uniquely identified by a unique ID.
053: * Only suites installed or updated using this API appear
054: * in the list of known suites.
055: */
056: public class MIDletSuiteStorage {
057:
058: /** This class has a different security domain than the MIDlet suite. */
059: private static SecurityToken classSecurityToken;
060:
061: /** This is the master storage object to synchronize all accesses */
062: private static MIDletSuiteStorage masterStorage;
063:
064: /**
065: * Initializes the security token for this class, so it can
066: * perform actions that a normal MIDlet Suite cannot.
067: *
068: * @param token security token for this class.
069: */
070: public static void initSecurityToken(SecurityToken token) {
071: if (classSecurityToken != null) {
072: return;
073: }
074:
075: classSecurityToken = token;
076: MIDletSuiteImpl.initSecurityToken(classSecurityToken);
077: }
078:
079: /**
080: * Returns a reference to the singleton MIDlet suite storage object.
081: *
082: * @return the storage reference
083: *
084: * @exception SecurityException if the caller does not have permission
085: * to install software
086: */
087: public static MIDletSuiteStorage getMIDletSuiteStorage()
088: throws SecurityException {
089: MIDletSuite midletSuite = MIDletStateHandler
090: .getMidletStateHandler().getMIDletSuite();
091:
092: if (midletSuite == null) {
093: throw new IllegalStateException(
094: "This method can't be called before "
095: + "a suite is started.");
096: }
097:
098: midletSuite.checkIfPermissionAllowed(Permissions.AMS);
099:
100: return getMasterStorage();
101: }
102:
103: /**
104: * Returns a reference to the singleton MIDlet suite storage object.
105: *
106: * @param securityToken security token of the calling class
107: *
108: * @return the storage reference
109: *
110: * @exception SecurityException if the caller does not have permission
111: * to manage midlets
112: */
113: public static MIDletSuiteStorage getMIDletSuiteStorage(
114: SecurityToken securityToken) throws SecurityException {
115: securityToken.checkIfPermissionAllowed(Permissions.AMS);
116:
117: return getMasterStorage();
118: }
119:
120: /**
121: * Java interface for midp_suiteid2pcsl_string().
122: *
123: * @param suiteId unique ID of the suite
124: *
125: * @return string representation of the given suiteId
126: */
127: public static native String suiteIdToString(int suiteId);
128:
129: /**
130: * Returns a reference to the singleton storage object.
131: *
132: * @return the storage reference
133: */
134: private static MIDletSuiteStorage getMasterStorage() {
135: if (masterStorage == null) {
136: masterStorage = new MIDletSuiteStorage();
137:
138: int status = loadSuitesIcons0();
139: if (Logging.REPORT_LEVEL <= Logging.ERROR) {
140: if (status != 0) {
141: Logging.report(Logging.ERROR, LogChannels.LC_AMS,
142: "Can't load the cached icons, error code"
143: + status);
144: }
145: }
146: }
147:
148: return masterStorage;
149: }
150:
151: /**
152: * Private constructor to prevent outside instantiation.
153: */
154: private MIDletSuiteStorage() {
155: }
156:
157: /**
158: * Gets the MIDlet Suite from storage, and selects one midlet to be run.
159: *
160: * @param id the unique ID of the suite given
161: * by the installer when it was downloaded
162: * @param update true is this MIDletSuite need to be updated
163: *
164: * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
165: * locked; MIDletSuiteCorruptedException is thrown if the MIDletSuite is
166: * corrupted
167: *
168: * @return MIDlet Suite reference
169: */
170: public synchronized MIDletSuiteImpl getMIDletSuite(int id,
171: boolean update) throws MIDletSuiteLockedException,
172: MIDletSuiteCorruptedException {
173: if (!suiteExists(id)) {
174: return null;
175: }
176:
177: MIDletSuiteImpl.lockMIDletSuite(id, update);
178:
179: /*
180: * save on startup time, get the properties at first getProperty call
181: * and fill permissions on getPermission
182: */
183: return new MIDletSuiteImpl(id);
184: }
185:
186: /**
187: * Reads the basic information about the midlet suite from the storage.
188: *
189: * @param id unique ID of the suite
190: *
191: * @exception IOException if an the information cannot be read
192: * @exception IllegalArgumentException if suiteId is invalid
193: *
194: * @return MIDletSuiteInfo object with the suite's attributes
195: */
196: public synchronized MIDletSuiteInfo getMIDletSuiteInfo(int id)
197: throws IOException, IllegalArgumentException {
198:
199: MIDletSuiteInfo msi = new MIDletSuiteInfo(id);
200: getMIDletSuiteInfoImpl0(id, msi);
201:
202: return msi;
203: }
204:
205: /**
206: *
207: *
208: * @param suiteId unique identifier of the suite
209: * @param iconName the name of the icon to retrieve
210: *
211: * @return
212: */
213: public synchronized byte[] getMIDletSuiteIcon(int suiteId,
214: String iconName) {
215: byte[] iconBytes = null;
216:
217: if (iconName == null) {
218: return null;
219: }
220:
221: try {
222: iconBytes = getMIDletSuiteIcon0(suiteId, iconName);
223:
224: if (iconBytes == null) {
225: /* Search for icon in the image cache */
226: iconBytes = loadCachedIcon0(suiteId, iconName);
227: }
228:
229: if (iconBytes == null) {
230: /* Search for icon in the suite JAR */
231: iconBytes = JarReader.readJarEntry(
232: getMidletSuiteJarPath(suiteId), iconName);
233: }
234: } catch (Exception e) {
235: iconBytes = null;
236: }
237:
238: return iconBytes;
239: }
240:
241: /**
242: * Get the midlet suite's class path including a path to the MONET
243: * image of the specified suite and a path to the suite's jar file.
244: *
245: * @param id unique ID of the suite
246: *
247: * @return class path or null if the suite does not exist
248: */
249: public synchronized String[] getMidletSuiteClassPath(int id) {
250: String jarFile = getMidletSuiteJarPath(id);
251:
252: if (Constants.MONET_ENABLED
253: && id != MIDletSuite.INTERNAL_SUITE_ID) {
254: String bunFile = getMidletSuiteAppImagePath(id);
255: return new String[] { bunFile, jarFile };
256: }
257: return new String[] { jarFile };
258: }
259:
260: /**
261: * Loads the cached icons from the permanent storage into memory.
262: *
263: * @return status code (0 if no errors)
264: */
265: public static native int loadSuitesIcons0();
266:
267: /**
268: * Retrieves the cached icon from the icon cache.
269: *
270: * @param suiteId unique identifier of the suite
271: * @param iconName the name of the icon to retrieve
272: *
273: * @return cached image data if available, otherwise null
274: */
275: private static native byte[] getMIDletSuiteIcon0(int suiteId,
276: String iconName);
277:
278: /**
279: * Loads suite icon data from image cache.
280: *
281: * @param suiteId the ID of suite the icon belongs to
282: * @param iconName the name of the icon to be loaded
283: *
284: * @return cached image data if available, otherwise null
285: */
286: private static native byte[] loadCachedIcon0(int suiteId,
287: String iconName);
288:
289: /**
290: * Reads the basic information about the midlet suite from the storage.
291: *
292: * @param id unique ID of the suite
293: * @param msi object to fill
294: *
295: * @exception IOException if an the information cannot be read
296: * @exception IllegalArgumentException if suiteId is invalid
297: */
298: public native void getMIDletSuiteInfoImpl0(int id,
299: MIDletSuiteInfo msi) throws IOException,
300: IllegalArgumentException;
301:
302: /**
303: * Get the path for the MONET image of the specified suite.
304: *
305: * @param id unique ID of the suite
306: *
307: * @return image path or null if the suite does not exist
308: */
309: public synchronized native String getMidletSuiteAppImagePath(int id);
310:
311: /**
312: * Get the class path for a suite.
313: *
314: * @param id unique ID of the suite
315: *
316: * @return class path or null if the suite does not exist
317: */
318: public synchronized native String getMidletSuiteJarPath(int id);
319:
320: /**
321: * Gets the unique identifier of MIDlet suite.
322: *
323: * @param vendor name of the vendor that created the application, as
324: * given in a JAD file
325: * @param name name of the suite, as given in a JAD file
326: *
327: * @return suite ID of the midlet suite given by vendor and name
328: * or MIDletSuite.UNUSED_SUITE_ID if the suite does not exist
329: */
330: public native static int getSuiteID(String vendor, String name);
331:
332: // -------------- Installer related functionality ---------------
333:
334: /**
335: * Get the installation information of a suite.
336: *
337: * @param midletSuite Suite object
338: *
339: * @return installation information
340: *
341: * @exception IOException if an the information cannot be read
342: */
343: InstallInfo getInstallInfo(MIDletSuiteImpl midletSuite)
344: throws IOException {
345: return midletSuite.getInstallInfo();
346: }
347:
348: /**
349: * Tells if a suite exists.
350: *
351: * @param id ID of a suite
352: *
353: * @return true if a suite of the given storage name
354: * already exists on the system
355: *
356: * @exception MIDletSuiteCorruptedException is thrown if the
357: * MIDletSuite is corrupted
358: */
359: public native boolean suiteExists(int id)
360: throws MIDletSuiteCorruptedException;
361:
362: /**
363: * Returns a unique identifier of MIDlet suite.
364: * Constructed from the combination
365: * of the values of the <code>MIDlet-Name</code> and
366: * <code>MIDlet-Vendor</code> attributes.
367: *
368: * @return the platform-specific storage name of the application
369: * given by vendorName and appName
370: */
371: public native int createSuiteID();
372:
373: /**
374: * Stores or updates a midlet suite.
375: *
376: * @param installInfo structure containing the following information:<br>
377: * <pre>
378: * id - unique ID of the suite;
379: * jadUrl - where the JAD came from, can be null;
380: * jarUrl - where the JAR came from;
381: * jarFilename - name of the downloaded MIDlet suite jar file;
382: * suiteName - name of the suite;
383: * suiteVendor - vendor of the suite;
384: * authPath - authPath if signed, the authorization path starting
385: * with the most trusted authority;
386: * domain - security domain of the suite;
387: * trusted - true if suite is trusted;
388: * verifyHash - may contain hash value of the suite with
389: * preverified classes or may be NULL;
390: * </pre>
391: *
392: * @param suiteSettings structure containing the following information:<br>
393: * <pre>
394: * permissions - permissions for the suite;
395: * pushInterruptSetting - defines if this MIDlet suite interrupt
396: * other suites;
397: * pushOptions - user options for push interrupts;
398: * suiteId - unique ID of the suite, must be equal to the one given
399: * in installInfo;
400: * boolean enabled - if true, MIDlet from this suite can be run;
401: * </pre>
402: *
403: * @param msi structure containing the following information:<br>
404: * <pre>
405: * suiteId - unique ID of the suite, must be equal to the value given
406: * in installInfo and suiteSettings parameters;
407: * storageId - ID of the storage where the MIDlet should be installed;
408: * numberOfMidlets - number of midlets in the suite;
409: * displayName - the suite's name to display to the user;
410: * midletToRunClassName - the midlet's class name if the suite contains
411: * only one midlet, ignored otherwise;
412: * iconName - name of the icon for this suite.
413: * </pre>
414: *
415: * @param jadProps properties defined in the application descriptor
416: *
417: * @param jarProps properties of the manifest
418: *
419: * @exception IOException is thrown, if an I/O error occurs during
420: * storing the suite
421: * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
422: * locked
423: */
424: public synchronized void storeSuite(InstallInfo installInfo,
425: SuiteSettings suiteSettings, MIDletSuiteInfo msi,
426: Properties jadProps, Properties jarProps)
427: throws IOException, MIDletSuiteLockedException {
428: /*
429: * Convert the property args to String arrays to save
430: * creating the native KNI code to access the object.
431: */
432: String[] strJadProperties = getPropertiesStrings(jadProps);
433: String[] strJarProperties = getPropertiesStrings(jarProps);
434:
435: nativeStoreSuite(installInfo, suiteSettings, msi,
436: strJadProperties, strJarProperties);
437: }
438:
439: /**
440: * Stores hash value of the suite with preverified classes
441: *
442: * @param id unique ID of the suite
443: * @param verifyHash hash value of the suite with preverified classes
444: */
445: public native void storeSuiteVerifyHash(int id, byte[] verifyHash);
446:
447: /**
448: * Disables a suite given its suite ID.
449: * <p>
450: * The method does not stop the suite if is in use. However any future
451: * attepts to run a MIDlet from this suite while disabled should fail.
452: *
453: * @param id suite ID for the installed package
454: *
455: * @exception IllegalArgumentException if the suite cannot be found
456: * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
457: * locked for updating
458: */
459: public native void disable(int id)
460: throws MIDletSuiteLockedException;
461:
462: /**
463: * Enables a suite given its suite ID.
464: * <p>
465: * The method does update an suites that are currently loaded for
466: * settings or of application management purposes.
467: *
468: * @param id suite ID for the installed package
469: *
470: * @exception IllegalArgumentException if the suite cannot be found
471: * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
472: * locked for updating
473: */
474: public native void enable(int id) throws MIDletSuiteLockedException;
475:
476: /**
477: * Removes a software package given its suite ID.
478: * The content handler manager is called to remove any registrations,
479: * if any.
480: * <p>
481: * If the component is in use it must continue to be available
482: * to the other components that are using it. The resources it
483: * consumes must not be released until it is not in use.
484: *
485: * @param id suite ID for the installed package
486: *
487: * @exception IllegalArgumentException if the suite cannot be found
488: * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
489: * locked
490: */
491: public void remove(int id) throws MIDletSuiteLockedException {
492: remove0(id);
493:
494: /*
495: * If no exception occurs,
496: * remove the content handler registrations, if any.
497: */
498: CHManager.getManager(classSecurityToken).uninstall(id);
499: }
500:
501: /**
502: * Stores or updates a midlet suite.
503: *
504: * @param installInfo structure containing the following information:<br>
505: * <pre>
506: * id - unique ID of the suite;
507: * jadUrl - where the JAD came from, can be null;
508: * jarUrl - where the JAR came from;
509: * jarFilename - name of the downloaded MIDlet suite jar file;
510: * suiteName - name of the suite;
511: * suiteVendor - vendor of the suite;
512: * authPath - authPath if signed, the authorization path starting
513: * with the most trusted authority;
514: * domain - security domain of the suite;
515: * trusted - true if suite is trusted;
516: * verifyHash - may contain hash value of the suite with
517: * preverified classes or may be NULL;
518: * </pre>
519: *
520: * @param suiteSettings structure containing the following information:<br>
521: * <pre>
522: * permissions - permissions for the suite;
523: * pushInterruptSetting - defines if this MIDlet suite interrupt
524: * other suites;
525: * pushOptions - user options for push interrupts;
526: * suiteId - unique ID of the suite, must be equal to the one given
527: * in installInfo;
528: * boolean enabled - if true, MIDlet from this suite can be run;
529: * </pre>
530: *
531: * @param msi structure containing the following information:<br>
532: * <pre>
533: * suiteId - unique ID of the suite, must be equal to the value given
534: * in installInfo and suiteSettings parameters;
535: * storageId - ID of the storage where the MIDlet should be installed;
536: * numberOfMidlets - number of midlets in the suite;
537: * displayName - the suite's name to display to the user;
538: * midletToRunClassName - the midlet's class name if the suite contains
539: * only one midlet, ignored otherwise;
540: * iconName - name of the icon for this suite.
541: * </pre>
542: *
543: * @param jadProps properties the JAD as an array of strings in
544: * key/value pair order, can be null if jadUrl is null
545: *
546: * @param jarProps properties of the manifest as an array of strings
547: * in key/value pair order
548: *
549: * @exception IOException is thrown, if an I/O error occurs during
550: * storing the suite
551: * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
552: * locked
553: */
554: private native void nativeStoreSuite(InstallInfo installInfo,
555: SuiteSettings suiteSettings, MIDletSuiteInfo msi,
556: String[] jadProps, String[] jarProps) throws IOException,
557: MIDletSuiteLockedException;
558:
559: /**
560: * Native remove of a software package given its suite ID.
561: * <p>
562: * If the component is in use it must continue to be available
563: * to the other components that are using it. The resources it
564: * consumes must not be released until it is not in use.
565: *
566: * @param id suite ID for the installed package
567: *
568: * @exception IllegalArgumentException if the suite cannot be found
569: * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
570: * locked
571: */
572: private native void remove0(int id)
573: throws MIDletSuiteLockedException;
574:
575: /**
576: * Fill plain array with properties key/value String pairs.
577: * It's needed to simplify properties using in a native code.
578: *
579: * @param props properties to get Strings from
580: *
581: * @return array of Strings filled with property key/value pairs
582: */
583: static String[] getPropertiesStrings(Properties props) {
584: if (props != null) {
585: int size = props.size();
586: String[] res = new String[size * 2];
587: for (int i = 0, j = 0; i < size; i++) {
588: res[j++] = props.getKeyAt(i);
589: res[j++] = props.getValueAt(i);
590: }
591: return res;
592: } else
593: return null;
594: }
595:
596: // ------------ Graphical App Manager ------------------
597:
598: /**
599: * Saves any of the settings (security or others) that the user may have
600: * changed.
601: *
602: * @param id ID of the suite
603: * @param pushInterruptSetting push interrupt setting
604: * @param pushOptions push options
605: * @param permissions security permissions for the suite
606: *
607: * @exception IOException if an error happens while writing
608: */
609: public void saveSuiteSettings(int id, byte pushInterruptSetting,
610: int pushOptions, byte[] permissions) throws IOException {
611: SuiteSettings settings = new SuiteSettings(id);
612: settings.setPushInterruptSetting(pushInterruptSetting);
613: settings.setPushOptions(pushOptions);
614: settings.setPermissions(permissions);
615: settings.save();
616: }
617:
618: /**
619: * Gets the amount of storage on the device that this suite is using.
620: * This includes the JAD, JAR, management data, and RMS.
621: *
622: * @param id ID of a MIDlet suite
623: *
624: * @return number of bytes of storage the suite is using
625: */
626: public native int getStorageUsed(int id);
627:
628: /**
629: * List all installed software packages by storage name.
630: *
631: * @return an array of ints of the storage names for the
632: * installed packages
633: * @exception SecurityException if the caller does not have permission
634: * to see what software is installed
635: */
636: public synchronized int[] getListOfSuites() {
637: int n = getNumberOfSuites();
638: if (n < 0) {
639: if (Logging.REPORT_LEVEL <= Logging.ERROR) {
640: Logging.report(Logging.ERROR, LogChannels.LC_AMS,
641: "Error in getNumberOfSuites0(): returned -1!");
642: }
643: n = 0;
644: }
645:
646: int[] array = new int[n];
647:
648: if (n > 0) {
649: getSuiteList(array);
650: }
651:
652: return array;
653: }
654:
655: /**
656: * Returns an array of the names of record stores owned by the
657: * MIDlet suite.
658: *
659: * The order of RecordStore names returned is implementation
660: * dependent.
661: *
662: * @param suiteId ID of the MIDlet suite that owns the record store
663: *
664: * @return array of the names of record stores owned by the
665: * MIDlet suite or null if the MIDlet suite does not have
666: * any record stores
667: */
668: public String[] listRecordStores(int suiteId) {
669: return RecordStoreImpl.listRecordStores(classSecurityToken,
670: suiteId);
671: }
672:
673: /**
674: * Get the number of installed of MIDlet suites.
675: *
676: * @return the number of installed suites or -1 in case of error
677: */
678: private native int getNumberOfSuites();
679:
680: /**
681: * Retrieves the list of MIDlet suites and store them into a Vector
682: * object. Each element in the Vector is the storage name
683: * of an installed application.
684: *
685: * @param suites an empty array of suite IDs to fill, call
686: * getNumberOfSuites to know how big to make the array
687: */
688: private native void getSuiteList(int[] suites);
689: }
|