001: /*
002: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License version
007: * 2 only, as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful, but
010: * WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * General Public License version 2 for more details (a copy is
013: * included at /legal/license.txt).
014: *
015: * You should have received a copy of the GNU General Public License
016: * version 2 along with this work; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
018: * 02110-1301 USA
019: *
020: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
021: * Clara, CA 95054 or visit www.sun.com if you need additional
022: * information or have any questions.
023: */
024:
025: package com.sun.midp.jump.installer;
026:
027: import com.sun.jump.module.download.JUMPDownloadDescriptor;
028: import com.sun.jump.common.JUMPContent;
029: import com.sun.jump.module.installer.JUMPInstallerModule;
030: import java.io.IOException;
031: import java.net.URL;
032: import java.util.ArrayList;
033: import java.util.Map;
034: import java.util.Properties;
035:
036: import com.sun.midp.installer.InvalidJadException;
037: import com.sun.midp.jump.MIDletApplication;
038: import com.sun.midp.jump.JumpInit;
039: import com.sun.midp.jump.midletsuite.MIDletSuiteStorageAccessor;
040:
041: /**
042: * <code>JUMPInstallerModule</code> provides the ability to install
043: * content.
044: * Installers have to implement this interface. They can optionally derive from
045: * {@link com.sun.jump.module.contentstore.JUMPContentStore} in their
046: * implementation for flexible storage options and abstractions.
047: */
048: public class MIDLETInstallerImpl implements JUMPInstallerModule {
049:
050: static JUMPInstallerInterface installer = null;
051: static StorageAccessInterface suiteStore = null;
052:
053: private static String midpProfileKey = "microedition.profiles";
054: private static String midpHomeKey = "sun.midp.home.path";
055:
056: public void unload() {
057: }
058:
059: public void load(Map map) {
060:
061: // Check for some system properties and set them if there's no default.
062: // Need to do this before initializing MIDletSuiteStorageAccessor.
063:
064: // For "microedition.profiles" value.
065: // Set the property with the module configuration data if the value is provided.
066: // Else, check if the property is already set, and if not, set default.
067: String profilename = (String) map.get(midpProfileKey);
068: if (profilename != null) {
069: System.setProperty(midpProfileKey, profilename);
070: } else {
071: profilename = System.getProperty(midpProfileKey);
072: if (profilename == null || profilename.equals("")) {
073: System.setProperty(midpProfileKey, "MIDP-2.0"); // Default
074: }
075: }
076:
077: // For "sun.midp.home.path" value.
078: // Set the property with the configuration data if the value is provided.
079: // Else, check if the property is already set, and if not, set default.
080: String homeDir = (String) map.get(midpHomeKey);
081: if (homeDir != null) {
082: System.setProperty(midpHomeKey, homeDir);
083: } else {
084: homeDir = System.getProperty(midpHomeKey);
085: if (homeDir == null || homeDir.equals("")) {
086: String javahome = System.getProperty("java.home", ".");
087: System.setProperty(midpHomeKey, javahome
088: + "/midp/midp_fb"); // Default
089: }
090: }
091:
092: JumpInit.init();
093:
094: installer = new JUMPFileInstaller();
095:
096: suiteStore = new MIDletSuiteStorageAccessor();
097: }
098:
099: /**
100: * Install content specified by the given descriptor and location.
101: * @return the installed content
102: */
103: public JUMPContent[] install(URL location,
104: JUMPDownloadDescriptor desc) {
105: return installOrUpdate(location, desc, false);
106: }
107:
108: /**
109: * Update content from given location
110: */
111: public void update(JUMPContent content, URL location,
112: JUMPDownloadDescriptor desc) {
113: installOrUpdate(location, desc, true);
114: }
115:
116: private JUMPContent[] installOrUpdate(URL location,
117: JUMPDownloadDescriptor desc, boolean isUpdate) {
118:
119: String path = location.getPath().toLowerCase();
120:
121: // below for more details.
122: String bundleName = desc.getName();
123: if (bundleName != null) {
124: // We need to replace spaces because apparently java doesn't like
125: // jarfiles with spaces in the name. Any further string substitutions
126: // should be done here.
127: bundleName = bundleName.replace(' ', '_');
128: }
129:
130: try {
131:
132: Properties prop = desc.getApplications()[0];
133: String localJadFile = prop
134: .getProperty("JUMPApplication_localJadUrl");
135: String localJarFile = location.getPath();
136:
137: int suiteId = 0;
138:
139: if (localJadFile != null) {
140: suiteId = installer.verifyAndStoreSuite(desc
141: .getObjectURI(), null, localJadFile,
142: localJarFile, isUpdate);
143:
144: } else if (path.endsWith(".jar")) {
145: suiteId = installer.verifyAndStoreSuite(desc
146: .getObjectURI(), localJarFile, bundleName,
147: isUpdate);
148: } else {
149: System.err
150: .println("install() failed, path not a jar file: "
151: + location);
152: return null;
153: }
154:
155: // Install succeeded. Gather the installed midlet suite's info
156: // from suitestore and convert them to a list of JUMPContents.
157:
158: JUMPContent[] installed = suiteStore
159: .convertToMIDletApplications(suiteId);
160:
161: return installed;
162:
163: } catch (Throwable ex) {
164: handleInstallerException(ex);
165: }
166:
167: return null;
168:
169: }
170:
171: /**
172: * Uninstall content
173: */
174: public void uninstall(JUMPContent content) {
175: MIDletApplication midlet = (MIDletApplication) content;
176:
177: suiteStore.remove(midlet.getMIDletSuiteID());
178: }
179:
180: /**
181: * Get all installed content
182: */
183: public JUMPContent[] getInstalled() {
184:
185: ArrayList appslist = new ArrayList();
186: JUMPContent[] apps;
187:
188: int[] suiteIds = suiteStore.getInstalledMIDletSuiteIds();
189:
190: for (int i = 0; i < suiteIds.length; i++) {
191: apps = suiteStore.convertToMIDletApplications(suiteIds[i]);
192: for (int j = 0; j < apps.length; j++) {
193: appslist.add(apps[j]);
194: }
195: }
196:
197: return (JUMPContent[]) appslist.toArray(new JUMPContent[] {});
198: }
199:
200: /**
201: * Handles an installer exceptions.
202: *
203: * @param ex exception to handle
204: */
205: static void handleInstallerException(Throwable ex) {
206:
207: String message = null;
208:
209: //ex.printStackTrace();
210:
211: if (ex instanceof InvalidJadException) {
212: InvalidJadException ije = (InvalidJadException) ex;
213: int reason = ije.getReason();
214:
215: message = "** Error installing suite (" + reason + "): "
216: + messageForInvalidJadException(ije);
217: } else if (ex instanceof IOException) {
218: message = "** I/O Error installing suite: "
219: + ex.getMessage();
220: } else {
221: message = "** Error installing suite: " + ex.toString();
222: }
223:
224: if (message != null) {
225: System.err.println(message);
226: }
227: }
228:
229: /**
230: * Returns the associated message for the given exception.
231: * This function is here instead of in the exception its self because
232: * it not need on devices, it needed only on development platforms that
233: * have command line interface.
234: *
235: * @param ije reason reason code for the exception
236: *
237: * @return associated message for the given reason
238: */
239: static String messageForInvalidJadException(InvalidJadException ije) {
240: switch (ije.getReason()) {
241: case InvalidJadException.MISSING_PROVIDER_CERT:
242: case InvalidJadException.MISSING_SUITE_NAME:
243: case InvalidJadException.MISSING_VENDOR:
244: case InvalidJadException.MISSING_VERSION:
245: case InvalidJadException.MISSING_JAR_URL:
246: case InvalidJadException.MISSING_JAR_SIZE:
247: case InvalidJadException.MISSING_CONFIGURATION:
248: case InvalidJadException.MISSING_PROFILE:
249: return "A required attribute is missing";
250:
251: case InvalidJadException.SUITE_NAME_MISMATCH:
252: case InvalidJadException.VERSION_MISMATCH:
253: case InvalidJadException.VENDOR_MISMATCH:
254: return "A required suite ID attribute in the JAR manifest "
255: + "do not match the one in the JAD";
256:
257: case InvalidJadException.ATTRIBUTE_MISMATCH:
258: return "The value for "
259: + ije.getExtraData()
260: + " in the "
261: + "trusted JAR manifest did not match the one in the JAD";
262:
263: case InvalidJadException.CORRUPT_PROVIDER_CERT:
264: return "The content provider certificate cannot be decoded.";
265:
266: case InvalidJadException.UNKNOWN_CA:
267: return "The content provider certificate issuer "
268: + ije.getExtraData() + " is unknown.";
269:
270: case InvalidJadException.INVALID_PROVIDER_CERT:
271: return "The signature of the content provider certificate "
272: + "is invalid.";
273:
274: case InvalidJadException.CORRUPT_SIGNATURE:
275: return "The JAR signature cannot be decoded.";
276:
277: case InvalidJadException.INVALID_SIGNATURE:
278: return "The signature of the JAR is invalid.";
279:
280: case InvalidJadException.UNSUPPORTED_CERT:
281: return "The content provider certificate is not a supported "
282: + "version.";
283:
284: case InvalidJadException.EXPIRED_PROVIDER_CERT:
285: return "The content provider certificate is expired.";
286:
287: case InvalidJadException.EXPIRED_CA_KEY:
288: return "The public key of " + ije.getExtraData()
289: + " has expired.";
290:
291: case InvalidJadException.JAR_SIZE_MISMATCH:
292: return "The Jar downloaded was not the size in the JAD";
293:
294: case InvalidJadException.OLD_VERSION:
295: return "The application is an older version of one that is "
296: + "already installed";
297:
298: case InvalidJadException.NEW_VERSION:
299: return "The application is an newer version of one that is "
300: + "already installed";
301:
302: case InvalidJadException.INVALID_JAD_URL:
303: return "The JAD URL is invalid";
304:
305: case InvalidJadException.JAD_SERVER_NOT_FOUND:
306: return "JAD server not found";
307:
308: case InvalidJadException.JAD_NOT_FOUND:
309: return "JAD not found";
310:
311: case InvalidJadException.INVALID_JAR_URL:
312: return "The JAR URL in the JAD is invalid: "
313: + ije.getExtraData();
314:
315: case InvalidJadException.JAR_SERVER_NOT_FOUND:
316: return "JAR server not found: " + ije.getExtraData();
317:
318: case InvalidJadException.JAR_NOT_FOUND:
319: return "JAR not found: " + ije.getExtraData();
320:
321: case InvalidJadException.CORRUPT_JAR:
322: return "Corrupt JAR, error while reading: "
323: + ije.getExtraData();
324:
325: case InvalidJadException.INVALID_JAR_TYPE:
326: if (ije.getExtraData() != null) {
327: return "JAR did not have the correct media type, it had "
328: + ije.getExtraData();
329: }
330:
331: return "The server did not have a resource with an "
332: + "acceptable media type for the JAR URL. (code 406)";
333:
334: case InvalidJadException.INVALID_JAD_TYPE:
335: if (ije.getExtraData() != null) {
336: String temp = ije.getExtraData();
337:
338: if (temp.length() == 0) {
339: return "JAD did not have a media type";
340: }
341:
342: return "JAD did not have the correct media type, it had "
343: + temp;
344: }
345:
346: /*
347: * Should not happen, the accept field is not send
348: * when getting the JAD.
349: */
350: return "The server did not have a resource with an "
351: + "acceptable media type for the JAD URL. (code 406)";
352:
353: case InvalidJadException.INVALID_KEY:
354: return "The attribute key [" + ije.getExtraData()
355: + "] is not in the proper format";
356:
357: case InvalidJadException.INVALID_VALUE:
358: return "The value for attribute " + ije.getExtraData()
359: + " is not in the proper format";
360:
361: case InvalidJadException.INSUFFICIENT_STORAGE:
362: return "There is insufficient storage to install this suite";
363:
364: case InvalidJadException.UNAUTHORIZED:
365: return "Authentication required or failed";
366:
367: case InvalidJadException.JAD_MOVED:
368: return "The JAD to be installed is for an existing suite, "
369: + "but not from the same domain as the existing one: "
370: + ije.getExtraData();
371:
372: case InvalidJadException.CANNOT_AUTH:
373: return "Cannot authenticate with the server, unsupported scheme";
374:
375: case InvalidJadException.DEVICE_INCOMPATIBLE:
376: return "Either the configuration or profile is not supported.";
377:
378: case InvalidJadException.ALREADY_INSTALLED:
379: return "The JAD matches a version of a suite already installed.";
380:
381: case InvalidJadException.AUTHORIZATION_FAILURE:
382: return "The suite is not authorized for "
383: + ije.getExtraData();
384:
385: case InvalidJadException.PUSH_DUP_FAILURE:
386: return "The suite is in conflict with another application "
387: + "listening for network data on "
388: + ije.getExtraData();
389:
390: case InvalidJadException.PUSH_FORMAT_FAILURE:
391: return "Push attribute in incorrectly formated: "
392: + ije.getExtraData();
393:
394: case InvalidJadException.PUSH_PROTO_FAILURE:
395: return "Connection in push attribute is not supported: "
396: + ije.getExtraData();
397:
398: case InvalidJadException.PUSH_CLASS_FAILURE:
399: return "The class in push attribute not in a MIDlet-<n> "
400: + "attribute: " + ije.getExtraData();
401:
402: case InvalidJadException.TRUSTED_OVERWRITE_FAILURE:
403: return "Cannot update a trusted suite with an untrusted "
404: + "version";
405:
406: case InvalidJadException.INVALID_CONTENT_HANDLER:
407: return "Content handler attribute(s) incorrectly formatted: "
408: + ije.getExtraData();
409:
410: case InvalidJadException.CONTENT_HANDLER_CONFLICT:
411: return "Content handler would conflict with another handler: "
412: + ije.getExtraData();
413:
414: case InvalidJadException.CA_DISABLED:
415: return "The application can't be authorized because "
416: + ije.getExtraData() + " is disabled.";
417:
418: case InvalidJadException.UNSUPPORTED_CHAR_ENCODING:
419: return "Unsupported character encoding: "
420: + ije.getExtraData();
421: }
422:
423: return ije.getMessage();
424: }
425: }
|