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.scriptutil;
028:
029: import java.io.*;
030:
031: import javax.microedition.midlet.MIDlet;
032:
033: import com.sun.midp.configurator.Constants;
034:
035: import com.sun.midp.installer.*;
036:
037: import com.sun.midp.midlet.*;
038:
039: import com.sun.midp.midletsuite.*;
040:
041: /**
042: * Installs/Updates a suite, prints out the result and parameters to
043: * run the first MIDlet of the suite using runMidlet. Upon success
044: * write to standard output the suite ID and class name of the first
045: * MIDlet enclosed by brackets. ["suiteID" "class name"]
046: * <p>
047: * The MIDlet uses these application properties as arguments: </p>
048: * <ol>
049: * <li>arg-0: URL for the suite
050: * <li>arg-1: Used to override the default domain used when installing
051: * an unsigned suite. The default is maximum to allow the runtime API tests
052: * be performed automatically without tester interaction. The domain name
053: * may be followed by a colon and a list of permissions that must be allowed
054: * even if they are not listed in the MIDlet-Permissions attribute in the
055: * application descriptor file. Instead of the list a keyword "all" can be
056: * specified indicating that all permissions must be allowed, for example:
057: * operator:all.
058: * </ol>
059: */
060: public class HttpJadInstaller extends MIDlet implements Runnable {
061: /** URL of the test suite. */
062: String url;
063: /** The installer. */
064: HttpInstaller installer;
065:
066: /**
067: * Create and initialize the MIDlet.
068: */
069: public HttpJadInstaller() {
070: // The arg-<n> properties are generic command arguments
071: url = getAppProperty("arg-0");
072: if (url == null) {
073: System.err.println("URL argument missing.");
074: System.err.println("HTTP JAD installer arguments: "
075: + "<HTTP URL> [<domain for unsigned suites>]");
076:
077: notifyDestroyed();
078: return;
079: }
080:
081: installer = new HttpInstaller();
082:
083: // URL given as a argument, look for a domain arg and then start
084: String domain = getAppProperty("arg-1");
085: if (domain != null) {
086: String additionalPermissions = null;
087: int index = domain.indexOf(":");
088: int len = domain.length();
089:
090: if (index > 0 && index + 1 < len) {
091: additionalPermissions = domain
092: .substring(index + 1, len);
093: domain = domain.substring(0, index);
094: }
095:
096: installer.setUnsignedSecurityDomain(domain);
097: installer.setExtraPermissions(additionalPermissions);
098: }
099:
100: new Thread(this ).start();
101: }
102:
103: /**
104: * Start.
105: */
106: public void startApp() {
107: }
108:
109: /**
110: * Pause; there are no resources that need to be released.
111: */
112: public void pauseApp() {
113: }
114:
115: /**
116: * Destroy cleans up.
117: *
118: * @param unconditional is ignored; this object always
119: * destroys itself when requested.
120: */
121: public void destroyApp(boolean unconditional) {
122: }
123:
124: /** Install a MIDlet suite. */
125: public void run() {
126: int suiteId;
127: MIDletInfo midletInfo;
128:
129: try {
130: // force an overwrite and remove the RMS data
131: suiteId = installer.installJad(url,
132: Constants.INTERNAL_STORAGE_ID, true, true, null);
133: midletInfo = getFirstMIDletOfSuite(suiteId);
134:
135: System.out.println("*Installed suite " + midletInfo.name);
136: System.out.println("[" + suiteId + " "
137: + midletInfo.classname + "]");
138: } catch (Throwable t) {
139: handleInstallerException(t);
140: }
141:
142: notifyDestroyed();
143: }
144:
145: /**
146: * Returns the information of the first MIDlet of the newly installed
147: * suite.
148: *
149: * @param suiteId ID of the MIDlet Suite
150: *
151: * @return an object with the class name and display name of
152: * the suite's MIDlet-1 property
153: */
154: static MIDletInfo getFirstMIDletOfSuite(int suiteId) {
155: MIDletSuiteStorage midletSuiteStorage = MIDletSuiteStorage
156: .getMIDletSuiteStorage();
157: MIDletSuite ms = null;
158: String name = null;
159:
160: try {
161: ms = midletSuiteStorage.getMIDletSuite(suiteId, false);
162: name = ms.getProperty("MIDlet-1");
163: } catch (Exception e) {
164: throw new RuntimeException("midlet properties corrupted");
165: } finally {
166: if (ms != null) {
167: ms.close();
168: }
169: }
170:
171: if (name == null) {
172: throw new RuntimeException("MIDlet-1 missing");
173: }
174:
175: // found the entry now parse out the class name, and display name
176: return new MIDletInfo(name);
177: }
178:
179: /**
180: * Handles an installer exceptions.
181: *
182: * @param ex exception to handle
183: */
184: static void handleInstallerException(Throwable ex) {
185: String message = null;
186:
187: if (ex instanceof InvalidJadException) {
188: InvalidJadException ije = (InvalidJadException) ex;
189: int reason = ije.getReason();
190:
191: message = "** Error installing suite (" + reason + "): "
192: + messageForInvalidJadException(ije);
193: } else if (ex instanceof IOException) {
194: message = "** I/O Error installing suite: "
195: + ex.getMessage();
196: } else {
197: message = "** Error installing suite: " + ex.toString();
198: }
199:
200: if (message != null) {
201: System.err.println(message);
202: }
203: }
204:
205: /**
206: * Returns the associated message for the given exception.
207: * This function is here instead of in the exception its self because
208: * it not need on devices, it needed only on development platforms that
209: * have command line interface.
210: *
211: * @param ije reason reason code for the exception
212: *
213: * @return associated message for the given reason
214: */
215: static String messageForInvalidJadException(InvalidJadException ije) {
216: switch (ije.getReason()) {
217: case InvalidJadException.MISSING_PROVIDER_CERT:
218: case InvalidJadException.MISSING_SUITE_NAME:
219: case InvalidJadException.MISSING_VENDOR:
220: case InvalidJadException.MISSING_VERSION:
221: case InvalidJadException.MISSING_JAR_URL:
222: case InvalidJadException.MISSING_JAR_SIZE:
223: case InvalidJadException.MISSING_CONFIGURATION:
224: case InvalidJadException.MISSING_PROFILE:
225: return "A required attribute is missing";
226:
227: case InvalidJadException.SUITE_NAME_MISMATCH:
228: case InvalidJadException.VERSION_MISMATCH:
229: case InvalidJadException.VENDOR_MISMATCH:
230: return "A required suite ID attribute in the JAR manifest "
231: + "do not match the one in the JAD";
232:
233: case InvalidJadException.ATTRIBUTE_MISMATCH:
234: return "The value for "
235: + ije.getExtraData()
236: + " in the "
237: + "trusted JAR manifest did not match the one in the JAD";
238:
239: case InvalidJadException.CORRUPT_PROVIDER_CERT:
240: return "The content provider certificate cannot be decoded.";
241:
242: case InvalidJadException.UNKNOWN_CA:
243: return "The content provider certificate issuer "
244: + ije.getExtraData() + " is unknown.";
245:
246: case InvalidJadException.INVALID_PROVIDER_CERT:
247: return "The signature of the content provider certificate "
248: + "is invalid.";
249:
250: case InvalidJadException.CORRUPT_SIGNATURE:
251: return "The JAR signature cannot be decoded.";
252:
253: case InvalidJadException.INVALID_SIGNATURE:
254: return "The signature of the JAR is invalid.";
255:
256: case InvalidJadException.UNSUPPORTED_CERT:
257: return "The content provider certificate is not a supported "
258: + "version.";
259:
260: case InvalidJadException.EXPIRED_PROVIDER_CERT:
261: return "The content provider certificate is expired.";
262:
263: case InvalidJadException.EXPIRED_CA_KEY:
264: return "The public key of " + ije.getExtraData()
265: + " has expired.";
266:
267: case InvalidJadException.JAR_SIZE_MISMATCH:
268: return "The Jar downloaded was not the size in the JAD";
269:
270: case InvalidJadException.OLD_VERSION:
271: return "The application is an older version of one that is "
272: + "already installed";
273:
274: case InvalidJadException.NEW_VERSION:
275: return "The application is an newer version of one that is "
276: + "already installed";
277:
278: case InvalidJadException.INVALID_JAD_URL:
279: return "The JAD URL is invalid";
280:
281: case InvalidJadException.JAD_SERVER_NOT_FOUND:
282: return "JAD server not found";
283:
284: case InvalidJadException.JAD_NOT_FOUND:
285: return "JAD not found";
286:
287: case InvalidJadException.INVALID_JAR_URL:
288: return "The JAR URL in the JAD is invalid: "
289: + ije.getExtraData();
290:
291: case InvalidJadException.JAR_SERVER_NOT_FOUND:
292: return "JAR server not found: " + ije.getExtraData();
293:
294: case InvalidJadException.JAR_NOT_FOUND:
295: return "JAR not found: " + ije.getExtraData();
296:
297: case InvalidJadException.CORRUPT_JAR:
298: return "Corrupt JAR, error while reading: "
299: + ije.getExtraData();
300:
301: case InvalidJadException.INVALID_JAR_TYPE:
302: if (ije.getExtraData() != null) {
303: return "JAR did not have the correct media type, it had "
304: + ije.getExtraData();
305: }
306:
307: return "The server did not have a resource with an "
308: + "acceptable media type for the JAR URL. (code 406)";
309:
310: case InvalidJadException.INVALID_JAD_TYPE:
311: if (ije.getExtraData() != null) {
312: String temp = ije.getExtraData();
313:
314: if (temp.length() == 0) {
315: return "JAD did not have a media type";
316: }
317:
318: return "JAD did not have the correct media type, it had "
319: + temp;
320: }
321:
322: /*
323: * Should not happen, the accept field is not send
324: * when getting the JAD.
325: */
326: return "The server did not have a resource with an "
327: + "acceptable media type for the JAD URL. (code 406)";
328:
329: case InvalidJadException.INVALID_KEY:
330: return "The attribute key [" + ije.getExtraData()
331: + "] is not in the proper format";
332:
333: case InvalidJadException.INVALID_VALUE:
334: return "The value for attribute " + ije.getExtraData()
335: + " is not in the proper format";
336:
337: case InvalidJadException.INSUFFICIENT_STORAGE:
338: return "There is insufficient storage to install this suite";
339:
340: case InvalidJadException.UNAUTHORIZED:
341: return "Authentication required or failed";
342:
343: case InvalidJadException.JAD_MOVED:
344: return "The JAD to be installed is for an existing suite, "
345: + "but not from the same domain as the existing one: "
346: + ije.getExtraData();
347:
348: case InvalidJadException.CANNOT_AUTH:
349: return "Cannot authenticate with the server, unsupported scheme";
350:
351: case InvalidJadException.DEVICE_INCOMPATIBLE:
352: return "Either the configuration or profile is not supported.";
353:
354: case InvalidJadException.ALREADY_INSTALLED:
355: return "The JAD matches a version of a suite already installed.";
356:
357: case InvalidJadException.AUTHORIZATION_FAILURE:
358: return "The suite is not authorized for "
359: + ije.getExtraData();
360:
361: case InvalidJadException.PUSH_DUP_FAILURE:
362: return "The suite is in conflict with another application "
363: + "listening for network data on "
364: + ije.getExtraData();
365:
366: case InvalidJadException.PUSH_FORMAT_FAILURE:
367: return "Push attribute in incorrectly formated: "
368: + ije.getExtraData();
369:
370: case InvalidJadException.PUSH_PROTO_FAILURE:
371: return "Connection in push attribute is not supported: "
372: + ije.getExtraData();
373:
374: case InvalidJadException.PUSH_CLASS_FAILURE:
375: return "The class in push attribute not in a MIDlet-<n> "
376: + "attribute: " + ije.getExtraData();
377:
378: case InvalidJadException.TRUSTED_OVERWRITE_FAILURE:
379: return "Cannot update a trusted suite with an untrusted "
380: + "version";
381:
382: case InvalidJadException.INVALID_CONTENT_HANDLER:
383: return "Content handler attribute(s) incorrectly formatted: "
384: + ije.getExtraData();
385:
386: case InvalidJadException.CONTENT_HANDLER_CONFLICT:
387: return "Content handler would conflict with another handler: "
388: + ije.getExtraData();
389:
390: case InvalidJadException.CA_DISABLED:
391: return "The application can't be authorized because "
392: + ije.getExtraData() + " is disabled.";
393:
394: case InvalidJadException.UNSUPPORTED_CHAR_ENCODING:
395: return "Unsupported character encoding: "
396: + ije.getExtraData();
397: }
398:
399: return ije.getMessage();
400: }
401: }
|