Source Code Cross Referenced for Installer.java in  » 6.0-JDK-Modules » j2me » com » sun » midp » installer » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » com.sun.midp.installer 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *
0003:         *
0004:         * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006:         * 
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License version
0009:         * 2 only, as published by the Free Software Foundation.
0010:         * 
0011:         * This program is distributed in the hope that it will be useful, but
0012:         * WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014:         * General Public License version 2 for more details (a copy is
0015:         * included at /legal/license.txt).
0016:         * 
0017:         * You should have received a copy of the GNU General Public License
0018:         * version 2 along with this work; if not, write to the Free Software
0019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020:         * 02110-1301 USA
0021:         * 
0022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023:         * Clara, CA 95054 or visit www.sun.com if you need additional
0024:         * information or have any questions.
0025:         */
0026:
0027:        package com.sun.midp.installer;
0028:
0029:        import java.util.Vector;
0030:
0031:        import java.io.IOException;
0032:        import java.io.InputStream;
0033:        import java.io.OutputStream;
0034:        import java.io.ByteArrayInputStream;
0035:
0036:        import javax.microedition.io.ConnectionNotFoundException;
0037:
0038:        import com.sun.midp.security.SecurityHandler;
0039:        import com.sun.midp.security.SecurityToken;
0040:        import com.sun.midp.security.Permissions;
0041:
0042:        import com.sun.midp.main.MIDletSuiteVerifier;
0043:        import com.sun.midp.main.MIDletAppImageGenerator;
0044:
0045:        import com.sun.midp.midlet.MIDletStateHandler;
0046:        import com.sun.midp.midlet.MIDletSuite;
0047:
0048:        import com.sun.midp.midletsuite.MIDletSuiteStorage;
0049:        import com.sun.midp.midletsuite.MIDletSuiteImpl;
0050:        import com.sun.midp.midletsuite.MIDletInfo;
0051:        import com.sun.midp.midletsuite.MIDletSuiteInfo;
0052:        import com.sun.midp.midletsuite.InstallInfo;
0053:        import com.sun.midp.midletsuite.SuiteSettings;
0054:        import com.sun.midp.midletsuite.MIDletSuiteLockedException;
0055:        import com.sun.midp.midletsuite.MIDletSuiteCorruptedException;
0056:
0057:        import com.sun.midp.io.HttpUrl;
0058:        import com.sun.midp.io.Util;
0059:
0060:        import com.sun.midp.io.j2me.push.PushRegistryInternal;
0061:        import com.sun.midp.io.j2me.storage.RandomAccessStream;
0062:        import com.sun.midp.io.j2me.storage.File;
0063:
0064:        import com.sun.midp.rms.RecordStoreFactory;
0065:
0066:        import com.sun.midp.content.CHManager;
0067:
0068:        import com.sun.midp.log.Logging;
0069:        import com.sun.midp.log.LogChannels;
0070:
0071:        import com.sun.midp.configurator.Constants;
0072:
0073:        /**
0074:         * An Installer manages MIDlet suites and libraries
0075:         * present in a Java application environment.  An MIDlet suite
0076:         * distributed as a descriptor and JAR pair.
0077:         * The descriptor identifies the configuration and contains security
0078:         * information and the manifest of the JAR describes the contents.
0079:         * The implementation of an Installer is
0080:         * specific to the platform and provides access to
0081:         * procedures that make an MIDlet suite visible to users.
0082:         * <P>
0083:         * Each installed package is uniquely identified by a storage name
0084:         * constructed from the combination
0085:         * of the values of the <code>MIDlet-Name</code> and
0086:         * <code>MIDlet-Vendor</code> attributes.
0087:         * The syntax and content of the strings used to identify
0088:         * installed packages are implementation dependent.
0089:         * Only packages installed or upgraded using this API appear
0090:         * in the list of known packages.
0091:         *
0092:         */
0093:        public abstract class Installer {
0094:            /** Status code to signal connection to the JAD server was successful. */
0095:            public static final int DOWNLOADING_JAD = 1;
0096:
0097:            /** Status code to signal that another 1K of the JAD has been download. */
0098:            public static final int DOWNLOADED_1K_OF_JAD = 2;
0099:
0100:            /** Status code to signal connection to the JAR server was successful. */
0101:            public static final int DOWNLOADING_JAR = 3;
0102:
0103:            /** Status code to signal that another 1K of the JAR has been download. */
0104:            public static final int DOWNLOADED_1K_OF_JAR = 4;
0105:
0106:            /**
0107:             * Status code to signal that download is done and the suite is being
0108:             * verified.
0109:             */
0110:            public static final int VERIFYING_SUITE = 5;
0111:
0112:            /**
0113:             * Status code to signal that application image is being generating.
0114:             */
0115:            public static final int GENERATING_APP_IMAGE = 6;
0116:
0117:            /**
0118:             * Status code to signal that suite classes are being verified.
0119:             */
0120:            public static final int VERIFYING_SUITE_CLASSES = 7;
0121:
0122:            /**
0123:             * Status code for local writing of the verified MIDlet suite.
0124:             * Stopping the install at this point has no effect, so there user
0125:             * should not be given a chance to stop the install.
0126:             */
0127:            public static final int STORING_SUITE = 8;
0128:
0129:            /** Status code for corrupted suite */
0130:            public static final int CORRUPTED_SUITE = 9;
0131:
0132:            /** System property containing the supported microedition profiles */
0133:            protected static final String MICROEDITION_PROFILES = "microedition.profiles";
0134:
0135:            /** System property containing the microedition configuration */
0136:            protected static final String MICROEDITION_CONFIG = "microedition.configuration";
0137:
0138:            /** System property containing the microedition locale */
0139:            protected static final String MICROEDITION_LOCALE = "microedition.locale";
0140:
0141:            /** Media-Type for valid application descriptor files. */
0142:            public static final String JAD_MT = "text/vnd.sun.j2me.app-descriptor";
0143:
0144:            /** Media-Type for valid Jar file. */
0145:            public static final String JAR_MT_1 = "application/java";
0146:
0147:            /** Media-Type for valid Jar file. */
0148:            public static final String JAR_MT_2 = "application/java-archive";
0149:
0150:            /**
0151:             * Filename to save the JAR of the suite temporarily. This is used
0152:             * to avoid overwriting an existing JAR prior to verification.
0153:             */
0154:            protected static final String TMP_FILENAME = "installer.tmp";
0155:
0156:            /** Midlet suite signature verifier. */
0157:            protected Verifier verifier;
0158:
0159:            /** Holds the install state. */
0160:            protected InstallStateImpl state;
0161:
0162:            /** An alias for more state.installInfo to get more compact record. */
0163:            protected InstallInfo info;
0164:
0165:            /** An alias for more state.suiteSettings to get more compact record. */
0166:            protected SuiteSettings settings;
0167:
0168:            /** Holds the CLDC configuration string. */
0169:            protected String cldcConfig;
0170:
0171:            /** Holds the device's Runtime Execution Environment string. */
0172:            protected final String cldcRuntimeEnv = "MIDP.CLDC";
0173:
0174:            /** Holds the MIDP supported profiles. */
0175:            private Vector supportedProfiles;
0176:
0177:            /** Use this to be the security domain for unsigned suites. */
0178:            protected String unsignedSecurityDomain = Permissions.UNIDENTIFIED_DOMAIN_BINDING;
0179:
0180:            /**
0181:             * Include this permissions into the list of permissions
0182:             * given in MIDlet-Permissions jad attribute for unsigned
0183:             * suites.
0184:             */
0185:            protected String additionalPermissions;
0186:
0187:            /**
0188:             * Constructor of the Installer.
0189:             */
0190:            Installer() {
0191:                state = getInstallState();
0192:                verifier = new VerifierImpl(state);
0193:
0194:                /* Aliases for more compact record. */
0195:                info = state.installInfo;
0196:                settings = state.suiteSettings;
0197:            }
0198:
0199:            /**
0200:             * Creates an instance of InstallState of the appropriate type
0201:             * depending on the installer type. Should be overloaded in the
0202:             * inherited classes.
0203:             *
0204:             * @return an instance of class containing the installation state
0205:             */
0206:            protected InstallStateImpl getInstallState() {
0207:                if (state == null) {
0208:                    state = new InstallStateImpl();
0209:                    // IMPL_NOTE: "info" and "settings" aliases must be updated
0210:                    // after calling getInstallState().
0211:                }
0212:
0213:                return state;
0214:            }
0215:
0216:            /**
0217:             * Installs a software package from the given URL. The URL is assumed
0218:             * refer to an application descriptor.
0219:             * <p>
0220:             * If the component to be installed is the same as an existing
0221:             * component (by comparing the <code>MIDlet-Name</code>,
0222:             * <code>MIDlet-Vendor</code> attributes)
0223:             * then this install is an upgrade if the version number is greater
0224:             * than the current version.  If so, the new version replaces in its
0225:             * entirety the current version.
0226:             * <p>
0227:             * It is implementation dependent when the upgraded component is
0228:             * made available for use.
0229:             * <p>
0230:             * The implementation of install must be robust in the presence
0231:             * of failures such as running out of memory.  If this method
0232:             * throws an exception then the package must <em>not</em> be installed
0233:             * and any previous version of the component must be left intact
0234:             * and operational.
0235:             * <p>
0236:             * To receive status updates and installer warnings, provide an install
0237:             * listener. If no listener is provided all warnings will be thrown
0238:             * as exceptions.
0239:             *
0240:             * @param location the URL from which the application descriptor can be
0241:             *        updated
0242:             * @param storageId ID of the storage where the suite should be saved
0243:             * @param force if <code>true</code> the MIDlet suite components to be
0244:             *              installed will overwrite any existing components without
0245:             *              any version comparison
0246:             * @param removeRMS if <code>true</code> and existing RMS data will be
0247:             *              removed when overwriting an existing suite
0248:             * @param installListener object to receive status updates and install
0249:             *     warnings, can be null
0250:             *
0251:             * @return the unique ID of the installed package.
0252:             *
0253:             * @exception ConnectionNotFoundException if JAD URL is invalid
0254:             * @exception IOException is thrown if any error prevents the installation
0255:             *   of the MIDlet suite, including being unable to access the application
0256:             *   descriptor or JAR
0257:             * @exception InvalidJadException if the downloaded application descriptor
0258:             *   is invalid
0259:             * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
0260:             * locked
0261:             * @exception SecurityException if the caller does not have permission
0262:             *   to install software
0263:             * @exception IllegalArgumentException is thrown, if the location of the
0264:             * descriptor file is not specified
0265:             */
0266:            public int installJad(String location, int storageId,
0267:                    boolean force, boolean removeRMS,
0268:                    InstallListener installListener) throws IOException,
0269:                    InvalidJadException, MIDletSuiteLockedException,
0270:                    SecurityException {
0271:
0272:                info.jadUrl = location;
0273:                state.force = force;
0274:                state.removeRMS = removeRMS;
0275:                state.nextStep = 1;
0276:                state.listener = installListener;
0277:                state.chmanager = CHManager.getManager(null);
0278:                state.storageId = storageId;
0279:
0280:                return performInstall();
0281:            }
0282:
0283:            /**
0284:             * Installs a software package from the given URL. The URL is assumed
0285:             * refer to a JAR.
0286:             * <p>
0287:             * If the component to be installed is the same as an existing
0288:             * component (by comparing the <code>MIDlet-Name</code>,
0289:             * <code>MIDlet-Vendor</code> attributes)
0290:             * then this install is an upgrade if the version number is greater
0291:             * than the current version.  If so, the new version replaces in its
0292:             * entirety the current version.
0293:             * <p>
0294:             * It is implementation dependent when the upgraded component is
0295:             * made available for use.
0296:             * <p>
0297:             * The implementation of install must be robust in the presence
0298:             * of failures such as running out of memory.  If this method
0299:             * throws an exception then the package must <em>not</em> be installed
0300:             * and any previous version of the component must be left intact
0301:             * and operational.
0302:             * <p>
0303:             * To receive status updates and installer warnings, provide an install
0304:             * listener. If no listener is provided all warnings will be thrown
0305:             * as exceptions.
0306:             *
0307:             * @param location the URL from which the JAR can be updated
0308:             * @param name the name of the suite to be updated
0309:             * @param storageId ID of the storage where the suite should be saved
0310:             * @param force if <code>true</code> the MIDlet suite components to be
0311:             *              installed will overwrite any existing components without
0312:             *              any version comparison
0313:             * @param removeRMS if <code>true</code> and existing RMS data will be
0314:             *              removed when overwriting an existing suite
0315:             * @param installListener object to receive status updates and install
0316:             *     warnings, can be null
0317:             *
0318:             * @return the unique ID of the installed package.
0319:             *
0320:             * @exception IOException is thrown if any error prevents the installation
0321:             *   of the MIDlet suite, including being unable to access the JAR
0322:             * @exception InvalidJadException if the downloaded JAR is invalid
0323:             * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
0324:             * locked
0325:             * @exception SecurityException if the caller does not have permission
0326:             *   to install software
0327:             * @exception IllegalArgumentException is thrown, if the location of the
0328:             * JAR specified
0329:             */
0330:            public int installJar(String location, String name, int storageId,
0331:                    boolean force, boolean removeRMS,
0332:                    InstallListener installListener) throws IOException,
0333:                    InvalidJadException, MIDletSuiteLockedException {
0334:
0335:                if (location == null || location.length() == 0) {
0336:                    throw new IllegalArgumentException(
0337:                            "Must specify URL of .jar file");
0338:                }
0339:
0340:                info.jadUrl = null;
0341:                info.jarUrl = location;
0342:                info.suiteName = name;
0343:                state.force = force;
0344:                state.removeRMS = removeRMS;
0345:                state.file = new File();
0346:                state.nextStep = 5;
0347:                state.listener = installListener;
0348:                state.chmanager = CHManager.getManager(null);
0349:                state.storageId = storageId;
0350:
0351:                return performInstall();
0352:            }
0353:
0354:            /**
0355:             * Performs an install.
0356:             *
0357:             * @return the unique name of the installed package
0358:             *
0359:             * @exception IOException is thrown, if an I/O error occurs during
0360:             * descriptor or jar file download
0361:             * @exception InvalidJadException is thrown, if the descriptor file is not
0362:             * properly formatted or does not contain the required
0363:             * information
0364:             * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
0365:             * locked
0366:             * @exception IllegalArgumentException is thrown, if the
0367:             * descriptor file is not specified
0368:             */
0369:            protected int performInstall() throws IOException,
0370:                    InvalidJadException, MIDletSuiteLockedException {
0371:
0372:                state.midletSuiteStorage = MIDletSuiteStorage
0373:                        .getMIDletSuiteStorage();
0374:
0375:                /* Disable push interruptions during install. */
0376:                PushRegistryInternal.enablePushLaunch(false);
0377:
0378:                try {
0379:                    state.startTime = System.currentTimeMillis();
0380:
0381:                    while (state.nextStep < 9) {
0382:                        /*
0383:                         * clear the previous warning, so we can tell if another has
0384:                         * happened
0385:                         */
0386:                        state.exception = null;
0387:
0388:                        if (state.stopInstallation) {
0389:                            postInstallMsgBackToProvider(OtaNotifier.USER_CANCELLED_MSG);
0390:                            throw new IOException("stopped");
0391:                        }
0392:
0393:                        switch (state.nextStep) {
0394:                        case 1:
0395:                            installStep1();
0396:                            break;
0397:
0398:                        case 2:
0399:                            installStep2();
0400:                            break;
0401:
0402:                        case 3:
0403:                            installStep3();
0404:                            break;
0405:
0406:                        case 4:
0407:                            installStep4();
0408:                            break;
0409:
0410:                        case 5:
0411:                            installStep5();
0412:                            break;
0413:
0414:                        case 6:
0415:                            installStep6();
0416:                            break;
0417:
0418:                        case 7:
0419:                            installStep7();
0420:                            break;
0421:
0422:                        case 8:
0423:                            installStep8();
0424:                            break;
0425:
0426:                        default:
0427:                            // for safety/completeness.
0428:                            Logging.report(Logging.CRITICAL,
0429:                                    LogChannels.LC_AMS,
0430:                                    "Installer: Unknown step: "
0431:                                            + state.nextStep);
0432:                            break;
0433:                        }
0434:
0435:                        if (state.exception != null) {
0436:                            if (state.listener == null) {
0437:                                throw state.exception;
0438:                            }
0439:
0440:                            if (!state.listener.warnUser(state)) {
0441:                                state.stopInstallation = true;
0442:                                postInstallMsgBackToProvider(OtaNotifier.USER_CANCELLED_MSG);
0443:                                throw state.exception;
0444:                            }
0445:                        }
0446:                    }
0447:                } finally {
0448:                    if (state.previousSuite != null) {
0449:                        state.previousSuite.close();
0450:                    }
0451:                    if (info.jarFilename != null) {
0452:                        if (state.file.exists(info.jarFilename)) {
0453:                            try {
0454:                                state.file.delete(info.jarFilename);
0455:                            } catch (Exception e) {
0456:                                if (Logging.REPORT_LEVEL <= Logging.WARNING) {
0457:                                    Logging.report(Logging.WARNING,
0458:                                            LogChannels.LC_AMS,
0459:                                            "delete file  threw an Exception");
0460:                                }
0461:                            }
0462:                        }
0463:                    }
0464:
0465:                    PushRegistryInternal.enablePushLaunch(true);
0466:                }
0467:
0468:                return info.id;
0469:            }
0470:
0471:            /**
0472:             * Downloads the JAD, save it in the install state.
0473:             * Parse the JAD, make sure it has
0474:             * the required properties, and save them in the install state.
0475:             *
0476:             * @exception IOException is thrown, if an I/O error occurs during
0477:             * descriptor or jar file download
0478:             * @exception InvalidJadException is thrown, if the descriptor file is not
0479:             * properly formatted or does not contain the required attributes
0480:             * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
0481:             * locked
0482:             * @exception IllegalArgumentException is thrown, if the
0483:             * descriptor file is not specified
0484:             */
0485:            private void installStep1() throws IOException,
0486:                    InvalidJadException, MIDletSuiteLockedException {
0487:
0488:                if (info.jadUrl == null || info.jadUrl.length() == 0) {
0489:                    throw new IllegalArgumentException(
0490:                            "Must specify URL of .jad file");
0491:                }
0492:
0493:                try {
0494:                    state.jad = downloadJAD();
0495:                } catch (OutOfMemoryError e) {
0496:                    try {
0497:                        postInstallMsgBackToProvider(OtaNotifier.INSUFFICIENT_MEM_MSG);
0498:                    } catch (Throwable t) {
0499:                        if (Logging.REPORT_LEVEL <= Logging.WARNING) {
0500:                            Logging.report(Logging.WARNING, LogChannels.LC_AMS,
0501:                                    "Throwable during posting install message");
0502:                        }
0503:                    }
0504:
0505:                    throw new InvalidJadException(
0506:                            InvalidJadException.TOO_MANY_PROPS);
0507:                }
0508:
0509:                if (state.exception != null) {
0510:                    return;
0511:                }
0512:
0513:                state.jadProps = new JadProperties();
0514:                try {
0515:                    state.jadProps.load(new ByteArrayInputStream(state.jad),
0516:                            state.jadEncoding);
0517:                } catch (OutOfMemoryError e) {
0518:                    state.jad = null;
0519:                    try {
0520:                        postInstallMsgBackToProvider(OtaNotifier.INSUFFICIENT_MEM_MSG);
0521:                    } catch (Throwable t) {
0522:                        if (Logging.REPORT_LEVEL <= Logging.WARNING) {
0523:                            Logging.report(Logging.WARNING, LogChannels.LC_AMS,
0524:                                    "Throwable during posting install message");
0525:                        }
0526:                    }
0527:
0528:                    throw new InvalidJadException(
0529:                            InvalidJadException.TOO_MANY_PROPS);
0530:                } catch (InvalidJadException ije) {
0531:                    state.jad = null;
0532:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0533:                    throw ije;
0534:                } catch (java.io.UnsupportedEncodingException uee) {
0535:                    state.jad = null;
0536:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0537:                    throw new InvalidJadException(
0538:                            InvalidJadException.UNSUPPORTED_CHAR_ENCODING,
0539:                            state.jadEncoding);
0540:                }
0541:
0542:                info.suiteName = state.jadProps
0543:                        .getProperty(MIDletSuite.SUITE_NAME_PROP);
0544:                if (info.suiteName == null || info.suiteName.length() == 0) {
0545:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0546:                    throw new InvalidJadException(
0547:                            InvalidJadException.MISSING_SUITE_NAME);
0548:                }
0549:
0550:                info.suiteVendor = state.jadProps
0551:                        .getProperty(MIDletSuite.VENDOR_PROP);
0552:                if (info.suiteVendor == null || info.suiteVendor.length() == 0) {
0553:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0554:                    throw new InvalidJadException(
0555:                            InvalidJadException.MISSING_VENDOR);
0556:                }
0557:
0558:                info.suiteVersion = state.jadProps
0559:                        .getProperty(MIDletSuite.VERSION_PROP);
0560:                if (info.suiteVersion == null
0561:                        || info.suiteVersion.length() == 0) {
0562:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0563:                    throw new InvalidJadException(
0564:                            InvalidJadException.MISSING_VERSION);
0565:                }
0566:
0567:                try {
0568:                    checkVersionFormat(info.suiteVersion);
0569:                } catch (NumberFormatException nfe) {
0570:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0571:                    throw new InvalidJadException(
0572:                            InvalidJadException.INVALID_VERSION);
0573:                }
0574:
0575:                info.id = state.midletSuiteStorage.createSuiteID();
0576:
0577:                checkPreviousVersion();
0578:                state.nextStep++;
0579:            }
0580:
0581:            /**
0582:             * If the JAD belongs to an installed suite, check the URL against the
0583:             * installed one.
0584:             */
0585:            private void installStep2() {
0586:                state.nextStep++;
0587:
0588:                if (state.isPreviousVersion) {
0589:                    checkForDifferentDomains(info.jadUrl);
0590:                }
0591:            }
0592:
0593:            /**
0594:             * Makes sure the suite can fit in storage.
0595:             *
0596:             * @exception IOException is thrown, if an I/O error occurs during
0597:             * descriptor or jar file download
0598:             * @exception InvalidJadException is thrown, if the descriptor file is not
0599:             * properly formatted or does not contain the required
0600:             */
0601:            private void installStep3() throws IOException, InvalidJadException {
0602:                String sizeString;
0603:                int dataSize;
0604:                int suiteSize;
0605:
0606:                sizeString = state.jadProps
0607:                        .getProperty(MIDletSuite.JAR_SIZE_PROP);
0608:                if (sizeString == null) {
0609:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0610:                    throw new InvalidJadException(
0611:                            InvalidJadException.MISSING_JAR_SIZE);
0612:                }
0613:
0614:                try {
0615:                    info.expectedJarSize = Integer.parseInt(sizeString);
0616:                } catch (NumberFormatException e) {
0617:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0618:                    throw new InvalidJadException(
0619:                            InvalidJadException.INVALID_VALUE);
0620:                }
0621:
0622:                sizeString = state.jadProps
0623:                        .getProperty(MIDletSuite.DATA_SIZE_PROP);
0624:                if (sizeString == null) {
0625:                    dataSize = 0;
0626:                } else {
0627:                    try {
0628:                        dataSize = Integer.parseInt(sizeString);
0629:                    } catch (NumberFormatException e) {
0630:                        postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0631:                        throw new InvalidJadException(
0632:                                InvalidJadException.INVALID_VALUE);
0633:                    }
0634:                }
0635:
0636:                /*
0637:                 * A suite is a jad + jar + manifest + url + data size.
0638:                 * lets say the manifest is the same size as the jad
0639:                 * since we do know at this point. the size is in bytes,
0640:                 * UTF-8 chars can be upto 3 bytes
0641:                 */
0642:                suiteSize = info.expectedJarSize + (state.jad.length * 2)
0643:                        + (info.jadUrl.length() * 3) + dataSize;
0644:                state.jad = null;
0645:
0646:                state.file = new File();
0647:
0648:                if (suiteSize > state.file
0649:                        .getBytesAvailableForFiles(state.storageId)) {
0650:                    postInstallMsgBackToProvider(OtaNotifier.INSUFFICIENT_MEM_MSG);
0651:
0652:                    // the size reported to the user should be in K and rounded up
0653:                    throw new InvalidJadException(
0654:                            InvalidJadException.INSUFFICIENT_STORAGE, Integer
0655:                                    .toString((suiteSize + 1023) / 1024));
0656:                }
0657:
0658:                info.jarUrl = state.jadProps
0659:                        .getProperty(MIDletSuite.JAR_URL_PROP);
0660:                if (info.jarUrl == null || info.jarUrl.length() == 0) {
0661:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0662:                    throw new InvalidJadException(
0663:                            InvalidJadException.MISSING_JAR_URL);
0664:                }
0665:
0666:                state.nextStep++;
0667:            }
0668:
0669:            /**
0670:             * Confirm installation with the user.
0671:             *
0672:             * @exception IOException is thrown, if the user cancels installation
0673:             */
0674:            private void installStep4() throws IOException {
0675:
0676:                synchronized (state) {
0677:                    /* One more check to see if user has already canceled */
0678:                    if (state.stopInstallation) {
0679:                        postInstallMsgBackToProvider(OtaNotifier.USER_CANCELLED_MSG);
0680:                        throw new IOException("stopped");
0681:                    }
0682:                    /*
0683:                     * Not canceled, so ignore cancel requests for now because below we
0684:                     * are going to ask anyway if user wants to install suite
0685:                     */
0686:                    state.ignoreCancel = true;
0687:                }
0688:
0689:                if (state.listener != null
0690:                        && !state.listener.confirmJarDownload(state)) {
0691:                    state.stopInstallation = true;
0692:                    postInstallMsgBackToProvider(OtaNotifier.USER_CANCELLED_MSG);
0693:                    throw new IOException("stopped");
0694:                }
0695:
0696:                synchronized (state) {
0697:                    /* Allow cancel requests again */
0698:                    state.ignoreCancel = false;
0699:                }
0700:                state.nextStep++;
0701:            }
0702:
0703:            /**
0704:             * Downloads the JAR, make sure it is the correct size, make sure
0705:             * the required attributes match the JAD's. Then store the
0706:             * application.
0707:             *
0708:             * @exception IOException is thrown, if an I/O error occurs during
0709:             * descriptor or jar file download
0710:             * @exception InvalidJadException is thrown, if the descriptor file is not
0711:             * properly formatted or does not contain the required
0712:             */
0713:            private void installStep5() throws IOException, InvalidJadException {
0714:                int bytesDownloaded;
0715:                MIDletInfo midletInfo;
0716:                String midlet;
0717:
0718:                // Send out delete notifications that have been queued, first
0719:                OtaNotifier.postQueuedDeleteMsgsBackToProvider(
0720:                        state.proxyUsername, state.proxyPassword);
0721:
0722:                // Save jar file to temp name; we need to do this to read the
0723:                // manifest entry, but, don't want to overwrite an existing
0724:                // application in case there are problems with the manifest
0725:                state.storageRoot = File.getStorageRoot(state.storageId);
0726:                info.jarFilename = state.storageRoot + TMP_FILENAME;
0727:
0728:                bytesDownloaded = downloadJAR(info.jarFilename);
0729:
0730:                if (state.exception != null) {
0731:                    return;
0732:                }
0733:
0734:                try {
0735:                    state.storage = new RandomAccessStream();
0736:
0737:                    state.installInfo.authPath = verifier.verifyJar(
0738:                            state.storage, info.jarFilename);
0739:
0740:                    if (state.listener != null) {
0741:                        state.listener.updateStatus(VERIFYING_SUITE, state);
0742:                    }
0743:
0744:                    // Create JAR Properties (From .jar file's MANIFEST)
0745:                    try {
0746:                        state.manifest = JarReader.readJarEntry(
0747:                                info.jarFilename, MIDletSuite.JAR_MANIFEST);
0748:                        if (state.manifest == null) {
0749:                            postInstallMsgBackToProvider(OtaNotifier.INVALID_JAR_MSG);
0750:                            throw new InvalidJadException(
0751:                                    InvalidJadException.CORRUPT_JAR,
0752:                                    MIDletSuite.JAR_MANIFEST);
0753:                        }
0754:                    } catch (OutOfMemoryError e) {
0755:                        try {
0756:                            postInstallMsgBackToProvider(OtaNotifier.INSUFFICIENT_MEM_MSG);
0757:                        } catch (Throwable t) {
0758:                            if (Logging.REPORT_LEVEL <= Logging.WARNING) {
0759:                                Logging
0760:                                        .report(Logging.WARNING,
0761:                                                LogChannels.LC_AMS,
0762:                                                "Throwable during posting the install message");
0763:                            }
0764:                        }
0765:
0766:                        throw new InvalidJadException(
0767:                                InvalidJadException.TOO_MANY_PROPS);
0768:                    } catch (IOException ioe) {
0769:                        postInstallMsgBackToProvider(OtaNotifier.INVALID_JAR_MSG);
0770:                        throw new InvalidJadException(
0771:                                InvalidJadException.CORRUPT_JAR,
0772:                                MIDletSuite.JAR_MANIFEST);
0773:                    }
0774:
0775:                    state.jarProps = new ManifestProperties();
0776:
0777:                    try {
0778:                        state.jarProps.load(new ByteArrayInputStream(
0779:                                state.manifest));
0780:                        state.manifest = null;
0781:                    } catch (OutOfMemoryError e) {
0782:                        state.manifest = null;
0783:                        try {
0784:                            postInstallMsgBackToProvider(OtaNotifier.INSUFFICIENT_MEM_MSG);
0785:                        } catch (Throwable t) {
0786:                            if (Logging.REPORT_LEVEL <= Logging.WARNING) {
0787:                                Logging
0788:                                        .report(Logging.WARNING,
0789:                                                LogChannels.LC_AMS,
0790:                                                "Throwable while posting install message ");
0791:                            }
0792:                        }
0793:
0794:                        throw new InvalidJadException(
0795:                                InvalidJadException.TOO_MANY_PROPS);
0796:                    } catch (InvalidJadException ije) {
0797:                        state.manifest = null;
0798:
0799:                        try {
0800:                            postInstallMsgBackToProvider(OtaNotifier.INVALID_JAR_MSG);
0801:                        } catch (Throwable t) {
0802:                            // ignore
0803:                        }
0804:
0805:                        throw ije;
0806:                    }
0807:
0808:                    for (int i = 1;; i++) {
0809:                        midlet = state.getAppProperty("MIDlet-" + i);
0810:                        if (midlet == null) {
0811:                            break;
0812:                        }
0813:
0814:                        /*
0815:                         * Verify the MIDlet class is present in the JAR
0816:                         * An exception thrown if not.
0817:                         * Do the proper install notify on an exception
0818:                         */
0819:                        try {
0820:                            midletInfo = new MIDletInfo(midlet);
0821:
0822:                            verifyMIDlet(midletInfo.classname);
0823:                        } catch (InvalidJadException ije) {
0824:                            if (ije.getReason() == InvalidJadException.INVALID_VALUE) {
0825:                                postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
0826:                            } else {
0827:                                postInstallMsgBackToProvider(OtaNotifier.INVALID_JAR_MSG);
0828:                            }
0829:                            throw ije;
0830:                        }
0831:                    }
0832:
0833:                    // move on to the next step after a warning
0834:                    state.nextStep++;
0835:
0836:                    // Check Manifest entries against .jad file
0837:                    if (info.jadUrl != null) {
0838:                        if (bytesDownloaded != info.expectedJarSize) {
0839:                            postInstallMsgBackToProvider(OtaNotifier.JAR_SIZE_MISMATCH_MSG);
0840:                            throw new InvalidJadException(
0841:                                    InvalidJadException.JAR_SIZE_MISMATCH);
0842:                        }
0843:
0844:                        if (!info.suiteName.equals(state.jarProps
0845:                                .getProperty(MIDletSuite.SUITE_NAME_PROP))) {
0846:                            postInstallMsgBackToProvider(OtaNotifier.ATTRIBUTE_MISMATCH_MSG);
0847:                            throw new InvalidJadException(
0848:                                    InvalidJadException.SUITE_NAME_MISMATCH);
0849:                        }
0850:
0851:                        if (!info.suiteVersion.equals(state.jarProps
0852:                                .getProperty(MIDletSuite.VERSION_PROP))) {
0853:                            postInstallMsgBackToProvider(OtaNotifier.ATTRIBUTE_MISMATCH_MSG);
0854:                            throw new InvalidJadException(
0855:                                    InvalidJadException.VERSION_MISMATCH);
0856:                        }
0857:
0858:                        if (!info.suiteVendor.equals(state.jarProps
0859:                                .getProperty(MIDletSuite.VENDOR_PROP))) {
0860:                            postInstallMsgBackToProvider(OtaNotifier.ATTRIBUTE_MISMATCH_MSG);
0861:                            throw new InvalidJadException(
0862:                                    InvalidJadException.VENDOR_MISMATCH);
0863:                        }
0864:                    } else {
0865:                        info.expectedJarSize = bytesDownloaded;
0866:                        info.suiteName = state.jarProps
0867:                                .getProperty(MIDletSuite.SUITE_NAME_PROP);
0868:                        if (info.suiteName == null
0869:                                || info.suiteName.length() == 0) {
0870:                            postInstallMsgBackToProvider(OtaNotifier.INVALID_JAR_MSG);
0871:                            throw new InvalidJadException(
0872:                                    InvalidJadException.MISSING_SUITE_NAME);
0873:                        }
0874:
0875:                        info.suiteVendor = state.jarProps
0876:                                .getProperty(MIDletSuite.VENDOR_PROP);
0877:                        if (info.suiteVendor == null
0878:                                || info.suiteVendor.length() == 0) {
0879:                            postInstallMsgBackToProvider(OtaNotifier.INVALID_JAR_MSG);
0880:                            throw new InvalidJadException(
0881:                                    InvalidJadException.MISSING_VENDOR);
0882:                        }
0883:
0884:                        info.suiteVersion = state.jarProps
0885:                                .getProperty(MIDletSuite.VERSION_PROP);
0886:                        if (info.suiteVersion == null
0887:                                || info.suiteVersion.length() == 0) {
0888:                            postInstallMsgBackToProvider(OtaNotifier.INVALID_JAR_MSG);
0889:                            throw new InvalidJadException(
0890:                                    InvalidJadException.MISSING_VERSION);
0891:                        }
0892:
0893:                        try {
0894:                            checkVersionFormat(info.suiteVersion);
0895:                        } catch (NumberFormatException nfe) {
0896:                            postInstallMsgBackToProvider(OtaNotifier.INVALID_JAR_MSG);
0897:                            throw new InvalidJadException(
0898:                                    InvalidJadException.INVALID_VERSION);
0899:                        }
0900:
0901:                        // if already installed, check the domain of the JAR URL
0902:
0903:                        info.id = state.midletSuiteStorage.createSuiteID();
0904:
0905:                        checkPreviousVersion();
0906:                    }
0907:                } catch (Exception e) {
0908:                    state.file.delete(info.jarFilename);
0909:
0910:                    if (e instanceof  IOException) {
0911:                        throw (IOException) e;
0912:                    }
0913:
0914:                    throw (RuntimeException) e;
0915:                }
0916:            }
0917:
0918:            /**
0919:             * If the JAR belongs to an installed suite if there was
0920:             * no JAD, check the URL against the installed one.
0921:             */
0922:            private void installStep6() {
0923:                state.nextStep++;
0924:
0925:                if (info.jadUrl == null && state.isPreviousVersion) {
0926:                    checkForDifferentDomains(info.jarUrl);
0927:                }
0928:            }
0929:
0930:            /**
0931:             * If some additional (i.e. that are not listed in jad) permissions must
0932:             * be allowed, add them to the value of MIDlet-Permissions attribute.
0933:             */
0934:            private void applyExtraPermissions() {
0935:                if (additionalPermissions != null) {
0936:                    String newPermissions = state.jadProps
0937:                            .getProperty(MIDletSuite.PERMISSIONS_PROP);
0938:
0939:                    if (newPermissions != null && newPermissions.length() > 0) {
0940:                        newPermissions += ",";
0941:                    }
0942:
0943:                    if ("all".equals(additionalPermissions)) {
0944:                        int i;
0945:                        byte[] domainPermissions = Permissions
0946:                                .forDomain(info.domain)[Permissions.MAX_LEVELS];
0947:
0948:                        newPermissions = "";
0949:
0950:                        for (i = 0; i < Permissions.NUMBER_OF_PERMISSIONS - 1; i++) {
0951:                            if (domainPermissions[i] != Permissions.NEVER) {
0952:                                newPermissions += Permissions.getName(i) + ",";
0953:                            }
0954:                        }
0955:
0956:                        // the same for the last permission, but without ","
0957:                        if (domainPermissions[i] != Permissions.NEVER) {
0958:                            newPermissions += Permissions.getName(i);
0959:                        }
0960:                    } else {
0961:                        newPermissions += additionalPermissions;
0962:                    }
0963:
0964:                    state.jadProps.setProperty(MIDletSuite.PERMISSIONS_PROP,
0965:                            newPermissions);
0966:
0967:                    /*
0968:                     * If the Midlet-Permissions attribute presents in there
0969:                     * manifest, it must be the same as in jad because the suite
0970:                     * is trusted.
0971:                     */
0972:                    String jarPermissions = state.jarProps
0973:                            .getProperty(MIDletSuite.PERMISSIONS_PROP);
0974:
0975:                    if (jarPermissions != null) {
0976:                        state.jarProps.setProperty(
0977:                                MIDletSuite.PERMISSIONS_PROP, newPermissions);
0978:                    }
0979:                }
0980:            }
0981:
0982:            /**
0983:             * Checks the permissions and store the suite.
0984:             *
0985:             * @exception IOException is thrown, if an I/O error occurs during
0986:             * storing the suite
0987:             * @exception InvalidJadException is thrown, if the there is
0988:             * permission problem
0989:             */
0990:            private void installStep7() throws IOException, InvalidJadException {
0991:
0992:                try {
0993:                    if (info.authPath != null) {
0994:                        // suite was signed
0995:                        info.domain = verifier
0996:                                .getSecurityDomainName(info.authPath[0]);
0997:                        if (state.listener != null
0998:                                && !state.listener.confirmAuthPath(state)) {
0999:                            state.stopInstallation = true;
1000:                            postInstallMsgBackToProvider(OtaNotifier.USER_CANCELLED_MSG);
1001:                            throw new IOException("stopped");
1002:                        }
1003:                    } else {
1004:                        info.domain = unsignedSecurityDomain;
1005:                    }
1006:
1007:                    info.trusted = Permissions.isTrusted(info.domain);
1008:
1009:                    // Do not overwrite trusted suites with untrusted ones
1010:                    if (!info.trusted && state.isPreviousVersion
1011:                            && state.previousSuite.isTrusted()) {
1012:
1013:                        postInstallMsgBackToProvider(OtaNotifier.AUTHORIZATION_FAILURE_MSG);
1014:
1015:                        /*
1016:                         * state.previousInstallInfo.authPath can be null in the case
1017:                         * if the previously installed suite was not signed but its
1018:                         * domain was set to some trusted one by AutoTester using
1019:                         * setUnsignedSecurityDomain().
1020:                         */
1021:                        throw new InvalidJadException(
1022:                                InvalidJadException.TRUSTED_OVERWRITE_FAILURE,
1023:                                state.previousInstallInfo.authPath != null ? state.previousInstallInfo.authPath[0]
1024:                                        : "");
1025:                    }
1026:
1027:                    /*
1028:                     * The unidentified suites do not get checked for requested
1029:                     * permissions.
1030:                     */
1031:                    if (Permissions.UNIDENTIFIED_DOMAIN_BINDING
1032:                            .equals(info.domain)) {
1033:
1034:                        settings
1035:                                .setPermissions((Permissions
1036:                                        .forDomain(info.domain))[Permissions.CUR_LEVELS]);
1037:
1038:                        /*
1039:                         * To keep public key management simple, there is only one
1040:                         * trusted keystore. So it is possible that the CA for
1041:                         * the suite is untrusted. This may be done on purpose for
1042:                         * testing. This is OK, but do not confuse the user by saying
1043:                         * the untrusted suite is authorized, so set the CA name to
1044:                         * null.
1045:                         */
1046:                        info.authPath = null;
1047:                    } else {
1048:                        /*
1049:                         * For identified suites, make sure an properties duplicated in
1050:                         * both the manifest and JAD are the same.
1051:                         */
1052:                        if (info.jadUrl != null) {
1053:                            checkForJadManifestMismatches();
1054:                        }
1055:
1056:                        /*
1057:                         * This is needed by the AutoTester: sometimes it is required
1058:                         * to allow some permissions even if they are not listed in jad.
1059:                         */
1060:                        applyExtraPermissions();
1061:
1062:                        settings
1063:                                .setPermissions(getInitialPermissions(info.domain));
1064:                    }
1065:
1066:                    if (state.isPreviousVersion) {
1067:                        applyCurrentUserLevelPermissions(
1068:                                state.previousSuite.getPermissions(),
1069:                                (Permissions.forDomain(info.domain))[Permissions.MAX_LEVELS],
1070:                                settings.getPermissions());
1071:
1072:                        if (state.removeRMS) {
1073:                            // override suite comparisons, just remove RMS
1074:                            RecordStoreFactory.removeRecordStoresForSuite(null,
1075:                                    info.id);
1076:                        } else {
1077:                            processPreviousRMS();
1078:                        }
1079:                    }
1080:
1081:                    state.securityHandler = new SecurityHandler(settings
1082:                            .getPermissions(), info.domain);
1083:
1084:                    checkRuntimeEnv();
1085:                    checkConfiguration();
1086:                    matchProfile();
1087:
1088:                    try {
1089:                        state.chmanager.preInstall(this , (InstallState) state,
1090:                                (MIDletSuite) state,
1091:                                (info.authPath == null ? null
1092:                                        : info.authPath[0]));
1093:                    } catch (InvalidJadException jex) {
1094:                        // Post the correct install notify msg back to the server
1095:                        String msg = OtaNotifier.INVALID_CONTENT_HANDLER;
1096:                        if (jex.getReason() == InvalidJadException.CONTENT_HANDLER_CONFLICT) {
1097:                            msg = OtaNotifier.CONTENT_HANDLER_CONFLICT;
1098:                        }
1099:
1100:                        postInstallMsgBackToProvider(msg);
1101:                        throw jex;
1102:                    } catch (SecurityException se) {
1103:                        postInstallMsgBackToProvider(OtaNotifier.AUTHORIZATION_FAILURE_MSG);
1104:
1105:                        // since our state object put the permission in message
1106:                        throw new InvalidJadException(
1107:                                InvalidJadException.AUTHORIZATION_FAILURE, se
1108:                                        .getMessage());
1109:                    }
1110:
1111:                    // make sure at least 1 second has passed
1112:                    try {
1113:                        long waitTime = 1000 - (System.currentTimeMillis() - state.startTime);
1114:
1115:                        if (waitTime > 0 && waitTime <= 1000) {
1116:                            Thread.sleep(waitTime);
1117:                        }
1118:                    } catch (InterruptedException ie) {
1119:                        // ignore
1120:                    }
1121:
1122:                    synchronized (state) {
1123:                        // this is the point of no return, one last check
1124:                        if (state.stopInstallation) {
1125:                            postInstallMsgBackToProvider(OtaNotifier.USER_CANCELLED_MSG);
1126:                            throw new IOException("stopped");
1127:                        }
1128:
1129:                        state.ignoreCancel = true;
1130:                    }
1131:
1132:                    if (state.listener != null) {
1133:                        state.listener.updateStatus(STORING_SUITE, state);
1134:                    }
1135:
1136:                    registerPushConnections();
1137:
1138:                    /** Do the Content Handler registration updates now */
1139:                    state.chmanager.install();
1140:
1141:                    /*
1142:                     * Store suite will remove the suite including push connections,
1143:                     * if there an error, but may not remove the temp jar file.
1144:                     */
1145:                    MIDletInfo midletInfo = state.getMidletInfo();
1146:                    String midletClassNameToRun = null, iconName;
1147:                    MIDletSuiteInfo msi;
1148:
1149:                    iconName = state.getAppProperty("MIDlet-Icon");
1150:                    if (iconName != null) {
1151:                        iconName.trim();
1152:                    }
1153:
1154:                    if (midletInfo != null) {
1155:                        midletClassNameToRun = midletInfo.classname;
1156:                        if (iconName == null) {
1157:                            // If an icon for the suite is not specified,
1158:                            // use the first midlet's icon.
1159:                            iconName = midletInfo.icon;
1160:                        }
1161:                    }
1162:
1163:                    msi = new MIDletSuiteInfo(info.id);
1164:                    msi.displayName = state.getDisplayName();
1165:                    msi.midletToRun = midletClassNameToRun;
1166:                    msi.numberOfMidlets = state.getNumberOfMIDlets();
1167:                    /* default is to enable a newly installed suite */
1168:                    msi.enabled = true;
1169:                    msi.trusted = info.trusted;
1170:                    msi.preinstalled = false;
1171:                    msi.iconName = iconName;
1172:                    msi.storageId = state.storageId;
1173:
1174:                    state.midletSuiteStorage.storeSuite(info, settings, msi,
1175:                            state.jadProps, state.jarProps);
1176:                } catch (Throwable e) {
1177:                    state.file.delete(info.jarFilename);
1178:                    if (e instanceof  IOException) {
1179:                        throw (IOException) e;
1180:                    }
1181:
1182:                    if (e instanceof  OutOfMemoryError) {
1183:                        try {
1184:                            postInstallMsgBackToProvider(OtaNotifier.INSUFFICIENT_MEM_MSG);
1185:                        } catch (Throwable t) {
1186:                            if (Logging.REPORT_LEVEL <= Logging.WARNING) {
1187:                                Logging
1188:                                        .report(Logging.WARNING,
1189:                                                LogChannels.LC_AMS,
1190:                                                "Throwable during posting install message");
1191:                            }
1192:                        }
1193:
1194:                        throw new InvalidJadException(
1195:                                InvalidJadException.TOO_MANY_PROPS);
1196:                    }
1197:
1198:                    throw (RuntimeException) e;
1199:                }
1200:
1201:                state.nextStep++;
1202:
1203:                try {
1204:                    postInstallMsgBackToProvider(OtaNotifier.SUCCESS_MSG);
1205:                } catch (Throwable t) {
1206:                    /*
1207:                     * The suite is successfully installed, but the post of the
1208:                     * status message failed. Do not let this failure prevent
1209:                     * the suite from being used.
1210:                     */
1211:                }
1212:            }
1213:
1214:            /**
1215:             * Installation time optimizations are to be done in this step.
1216:             * MONET optimization, VERIFY ONCE optimization, etc.
1217:             * This step is done after obligatory installation part,
1218:             * so the suite is downloaded, checked and stored by this moment.
1219:             */
1220:            private void installStep8() throws IOException {
1221:
1222:                // In case of installation from JAR the suite id as well as other
1223:                // properties are read from .jar file's MANIFEST rather then from
1224:                // JAD file. Only after that application image can be generated.
1225:                if (Constants.MONET_ENABLED) {
1226:                    if (state.listener != null) {
1227:                        state.listener
1228:                                .updateStatus(GENERATING_APP_IMAGE, state);
1229:                    }
1230:                    MIDletAppImageGenerator.createAppImage(info.id,
1231:                            state.midletSuiteStorage);
1232:                }
1233:                // Verification caching should be done if MONET disabled only
1234:                else if (Constants.VERIFY_ONCE) {
1235:                    if (state.listener != null) {
1236:                        state.listener.updateStatus(VERIFYING_SUITE_CLASSES,
1237:                                state);
1238:                    }
1239:                    // Preverify all suite classes
1240:                    // in the case of success store hash value of the suite
1241:                    try {
1242:                        info.verifyHash = MIDletSuiteVerifier
1243:                                .verifySuiteClasses(info.id,
1244:                                        state.midletSuiteStorage);
1245:                        if (info.verifyHash != null) {
1246:                            state.midletSuiteStorage.storeSuiteVerifyHash(
1247:                                    info.id, info.verifyHash);
1248:                        }
1249:                    } catch (Throwable t) {
1250:                        // Notify installation listener of verifcation error
1251:                        state.exception = new InvalidJadException(
1252:                                InvalidJadException.JAR_CLASSES_VERIFICATION_FAILED);
1253:                        if (state.listener != null) {
1254:                            state.listener.updateStatus(
1255:                                    VERIFYING_SUITE_CLASSES, state);
1256:                        }
1257:
1258:                        // Clean exception since this step is optional and its
1259:                        // problems shouldn't cause whole installation failure
1260:                        state.exception = null;
1261:                    }
1262:                }
1263:
1264:                state.nextStep++;
1265:            }
1266:
1267:            /**
1268:             * Verify that a class is present in the JAR file.
1269:             * If the classname is invalid or is not found an
1270:             * InvalidJadException is thrown.
1271:             * @param classname the name of the class to verify
1272:             * @exception InvalidJadException is thrown if the name is null or empty
1273:             * or if the file is not found
1274:             */
1275:            public void verifyMIDlet(String classname)
1276:                    throws InvalidJadException {
1277:                if (classname == null || classname.length() == 0) {
1278:                    throw new InvalidJadException(
1279:                            InvalidJadException.INVALID_VALUE);
1280:                }
1281:
1282:                String file = classname.replace('.', '/').concat(".class");
1283:
1284:                try {
1285:                    /* Attempt to read the MIDlet from the JAR file. */
1286:                    if (JarReader.readJarEntry(info.jarFilename, file) != null) {
1287:                        return; // File found, normal return
1288:                    }
1289:                    // Fall into throwing the exception
1290:                } catch (IOException ioe) {
1291:                    // Fall into throwing the exception
1292:                }
1293:                // Throw the InvalidJadException
1294:                throw new InvalidJadException(InvalidJadException.CORRUPT_JAR,
1295:                        file);
1296:            }
1297:
1298:            /**
1299:             * Downloads an application descriptor file from the given URL.
1300:             *
1301:             * @return a byte array representation of the file or null if not found
1302:             *
1303:             * @exception IOException is thrown if any error prevents the download
1304:             *   of the JAD
1305:             */
1306:            protected abstract byte[] downloadJAD() throws IOException;
1307:
1308:            /**
1309:             * Downloads an application archive file from the given URL into the
1310:             * given file. Automatically handle re-tries.
1311:             *
1312:             * @param filename name of the file to write. This file resides
1313:             *          in the storage area of the given application
1314:             *
1315:             * @return size of the JAR
1316:             *
1317:             * @exception IOException is thrown if any error prevents the download
1318:             *   of the JAR
1319:             */
1320:            protected abstract int downloadJAR(String filename)
1321:                    throws IOException;
1322:
1323:            /**
1324:             * If the JAD belongs to an installed suite, check the URL against the
1325:             * installed one. Set the state.exception if the user needs to be warned.
1326:             *
1327:             * @param url JAD or JAR URL of the suite being installed
1328:             */
1329:            protected void checkForDifferentDomains(String url) {
1330:                String previousUrl = state.previousInstallInfo.getDownloadUrl();
1331:                // perform a domain check not a straight compare
1332:                if (info.authPath == null && previousUrl != null) {
1333:                    HttpUrl old = new HttpUrl(previousUrl);
1334:                    HttpUrl current = new HttpUrl(url);
1335:
1336:                    if ((current.domain != null && old.domain == null)
1337:                            || (current.domain == null && old.domain != null)
1338:                            || (current.domain != null && old.domain != null && !current.domain
1339:                                    .regionMatches(true, 0, old.domain, 0,
1340:                                            old.domain.length()))) {
1341:                        /*
1342:                         * The jad is at new location, could be bad,
1343:                         * let the user decide
1344:                         */
1345:                        state.exception = new InvalidJadException(
1346:                                InvalidJadException.JAD_MOVED, previousUrl);
1347:                        return;
1348:                    }
1349:                }
1350:            }
1351:
1352:            /**
1353:             * See if there is an installed version of the suite being installed and
1354:             * if so, make an necessary checks. Will set state fields, including
1355:             * the exception field for warning the user.
1356:             *
1357:             * @exception InvalidJadException if the new version is formated
1358:             * incorrectly
1359:             * @exception MIDletSuiteLockedException is thrown, if the MIDletSuite is
1360:             * locked
1361:             */
1362:            protected void checkPreviousVersion() throws InvalidJadException,
1363:                    MIDletSuiteLockedException {
1364:
1365:                int id;
1366:                MIDletSuiteImpl midletSuite;
1367:                String installedVersion;
1368:                int cmpResult;
1369:
1370:                // Check if app already exists
1371:                id = MIDletSuiteStorage.getSuiteID(info.suiteVendor,
1372:                        info.suiteName);
1373:                if (id == MIDletSuite.UNUSED_SUITE_ID) {
1374:                    // there is no previous version
1375:                    return;
1376:                }
1377:
1378:                try {
1379:                    midletSuite = state.midletSuiteStorage.getMIDletSuite(id,
1380:                            true);
1381:
1382:                    if (midletSuite == null) {
1383:                        // there is no previous version
1384:                        return;
1385:                    }
1386:                    checkVersionFormat(info.suiteVersion);
1387:
1388:                    state.isPreviousVersion = true;
1389:
1390:                    // This is now an update, use the old ID
1391:                    info.id = id;
1392:
1393:                    state.previousSuite = midletSuite;
1394:                    state.previousInstallInfo = midletSuite.getInstallInfo();
1395:
1396:                    if (state.force) {
1397:                        // do not ask questions, force an overwrite
1398:                        return;
1399:                    }
1400:
1401:                    // If it does, check version information
1402:                    installedVersion = midletSuite
1403:                            .getProperty(MIDletSuite.VERSION_PROP);
1404:                    cmpResult = vercmp(info.suiteVersion, installedVersion);
1405:                    if (cmpResult < 0) {
1406:                        // older version, warn user
1407:                        state.exception = new InvalidJadException(
1408:                                InvalidJadException.OLD_VERSION,
1409:                                installedVersion);
1410:                        return;
1411:                    }
1412:
1413:                    if (cmpResult == 0) {
1414:                        // already installed, warn user
1415:                        state.exception = new InvalidJadException(
1416:                                InvalidJadException.ALREADY_INSTALLED,
1417:                                installedVersion);
1418:                        return;
1419:                    }
1420:
1421:                    // new version, warn user
1422:                    state.exception = new InvalidJadException(
1423:                            InvalidJadException.NEW_VERSION, installedVersion);
1424:                    return;
1425:                } catch (MIDletSuiteCorruptedException mce) {
1426:                    if (state.listener != null) {
1427:                        state.listener.updateStatus(CORRUPTED_SUITE, state);
1428:                    }
1429:                } catch (NumberFormatException nfe) {
1430:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
1431:                    throw new InvalidJadException(
1432:                            InvalidJadException.INVALID_VERSION);
1433:                }
1434:            }
1435:
1436:            /**
1437:             * Posts a status message back to the provider's URL in JAD.
1438:             *
1439:             * @param message status message to post
1440:             */
1441:            protected void postInstallMsgBackToProvider(String message) {
1442:                OtaNotifier.postInstallMsgBackToProvider(message, state,
1443:                        state.proxyUsername, state.proxyPassword);
1444:            }
1445:
1446:            /**
1447:             * Function that actually does the work of transferring file data.
1448:             * <p>
1449:             * Updates the listener every 1 K bytes.
1450:             * <p>
1451:             * If the amount of data to be read is larger than <code>maxDLSize</code>
1452:             * we will break the input into chunks no larger than
1453:             * <code>chunkSize</code>. This prevents the VM from running out of
1454:             * memory when processing large files.
1455:             *
1456:             * @param in the input stream to read from
1457:             * @param out the output stream to write to
1458:             * @param chunkSize size of piece to read from the input buffer
1459:             *
1460:             * @return number of bytes written to the output stream
1461:             *
1462:             * @exception IOException if any exceptions occur during transfer
1463:             * of data
1464:             */
1465:            protected int transferData(InputStream in, OutputStream out,
1466:                    int chunkSize) throws IOException {
1467:                byte[] buffer = new byte[chunkSize];
1468:                int bytesRead;
1469:                int totalBytesWritten = 0;
1470:
1471:                if (state.listener != null) {
1472:                    state.listener.updateStatus(state.beginTransferDataStatus,
1473:                            state);
1474:                }
1475:
1476:                try {
1477:                    for (int nextUpdate = totalBytesWritten + 1024;;) {
1478:                        bytesRead = in.read(buffer);
1479:
1480:                        if (state.listener != null
1481:                                && (bytesRead == -1 || totalBytesWritten
1482:                                        + bytesRead >= nextUpdate)) {
1483:
1484:                            synchronized (state) {
1485:                                if (state.stopInstallation) {
1486:                                    throw new IOException("stopped");
1487:                                }
1488:
1489:                                state.listener.updateStatus(
1490:                                        state.transferStatus, state);
1491:                            }
1492:
1493:                            nextUpdate = totalBytesWritten + 1024;
1494:                        }
1495:
1496:                        if (bytesRead == -1) {
1497:                            return totalBytesWritten;
1498:                        }
1499:
1500:                        out.write(buffer, 0, bytesRead);
1501:                        totalBytesWritten += bytesRead;
1502:                    }
1503:                } catch (IOException ioe) {
1504:                    if (state.stopInstallation) {
1505:                        postInstallMsgBackToProvider(OtaNotifier.USER_CANCELLED_MSG);
1506:                        throw new IOException("stopped");
1507:                    } else {
1508:                        throw ioe;
1509:                    }
1510:                }
1511:            }
1512:
1513:            /**
1514:             * Retrieves a scheme component of the given URL.
1515:             *
1516:             * @param url url to parse
1517:             * @param defaultScheme if the url has no scheme component, this one
1518:             *                      will be returned; may be null
1519:             *
1520:             * @return scheme component of the given URL
1521:             */
1522:            public static String getUrlScheme(String url, String defaultScheme) {
1523:                if (url == null) {
1524:                    return null;
1525:                }
1526:
1527:                /* this will parse any kind of URL, not only Http */
1528:                HttpUrl parsedUrl = new HttpUrl(url);
1529:
1530:                if (parsedUrl.scheme == null) {
1531:                    return defaultScheme;
1532:                }
1533:
1534:                return parsedUrl.scheme;
1535:            }
1536:
1537:            /**
1538:             * Retrieves a path component of the given URL.
1539:             *
1540:             * @param url url to parse
1541:             *
1542:             * @return path component of the given URL
1543:             */
1544:            public static String getUrlPath(String url) {
1545:                if (url == null) {
1546:                    return null;
1547:                }
1548:
1549:                /* this will parse any kind of URL, not only Http */
1550:                HttpUrl parsedUrl = new HttpUrl(url);
1551:                String path = parsedUrl.path;
1552:
1553:                /*
1554:                   IMPL_NOTE: In current implementation of HttpUrl
1555:                       the absolute path always begins with '/' which
1556:                       would make getUrlPath() produce the win32
1557:                       paths in the form "/C:/path/to/file" that is
1558:                       rejected by the filesystem.
1559:                       The initial '/' in 'path' is currently the only
1560:                       flag which allows to distinguish between absolute
1561:                       and relative url.
1562:                       Probably there should be a special flag in HttpUrl
1563:                       to distinguish between absolute and relative urls.
1564:                       Moreover it seems necessary to have platform-dependent
1565:                       conversion procedure from url path to filesystem path.
1566:                 */
1567:
1568:                if (path != null) {
1569:                    if (path.charAt(0) == '/') {
1570:                        path = path.substring(1, path.length());
1571:                    }
1572:                }
1573:
1574:                return path;
1575:            }
1576:
1577:            /**
1578:             * Compares two URLs for equality in sense that they have the same
1579:             * scheme, host and path.
1580:             *
1581:             * @param url1 the first URL for comparision
1582:             * @param url1 the second URL for comparision
1583:             *
1584:             * @return true if the scheme, host and path of the first given url
1585:             *              is identical to the scheme, host and path of the second
1586:             *              given url; false otherwise
1587:             */
1588:            protected abstract boolean isSameUrl(String url1, String url2);
1589:
1590:            /**
1591:             * If this is an update, make sure the RMS data is handle correctly
1592:             * according to the OTA spec.
1593:             * <p>
1594:             * From the OTA spec:
1595:             * <blockquote>
1596:             * The RMS record stores of a MIDlet suite being updated MUST be
1597:             * managed as follows:</p>
1598:             * <ul>
1599:             * <li>
1600:             *   If the cryptographic signer of the new MIDlet suite and the
1601:             *   original MIDlet suite are identical, then the RMS record
1602:             *   stores MUST be retained and made available to the new MIDlet
1603:             *   suite.</li>
1604:             * <li>
1605:             *   If the scheme, host, and path of the URL that the new
1606:             *   Application Descriptor is downloaded from is identical to the
1607:             *   scheme, host, and path of the URL the original Application
1608:             *   Descriptor was downloaded from, then the RMS MUST be retained
1609:             *   and made available to the new MIDlet suite.</li>
1610:             * <li>
1611:             *   If the scheme, host, and path of the URL that the new MIDlet
1612:             *   suite is downloaded from is identical to the scheme, host, and
1613:             *   path of the URL the original MIDlet suite was downloaded from,
1614:             *   then the RMS MUST be retained and made available to the new
1615:             *   MIDlet suite.</li>
1616:             * <li>
1617:             *   If the above statements are false, then the device MUST ask
1618:             *   the user whether the data from the original MIDlet suite
1619:             *   should be retained and made available to the new MIDlet
1620:             *   suite.</li>
1621:             * </ul>
1622:             * </blockquote>
1623:             *
1624:             * @exception IOException if the install is stopped
1625:             */
1626:            protected void processPreviousRMS() throws IOException {
1627:                if (!RecordStoreFactory.suiteHasRmsData(info.id)) {
1628:                    return;
1629:                }
1630:
1631:                if (state.previousInstallInfo.authPath != null
1632:                        && info.authPath != null
1633:                        && info.authPath[0]
1634:                                .equals(state.previousInstallInfo.authPath[0])) {
1635:                    // signers the same
1636:                    return;
1637:                }
1638:
1639:                if (isSameUrl(info.jadUrl, state.previousInstallInfo
1640:                        .getJadUrl())
1641:                        || isSameUrl(info.jarUrl, state.previousInstallInfo
1642:                                .getJarUrl())) {
1643:                    return;
1644:                }
1645:
1646:                // ask the user, if no listener assume no for user's answer
1647:                if (state.listener != null) {
1648:                    if (state.listener.keepRMS(state)) {
1649:                        // user wants to keep the data
1650:                        return;
1651:                    }
1652:                }
1653:
1654:                // this is a good place to check for a stop installing call
1655:                if (state.stopInstallation) {
1656:                    postInstallMsgBackToProvider(OtaNotifier.USER_CANCELLED_MSG);
1657:                    throw new IOException("stopped");
1658:                }
1659:
1660:                RecordStoreFactory.removeRecordStoresForSuite(null, info.id);
1661:            }
1662:
1663:            /**
1664:             * Stops the installation. If installer is not installing then this
1665:             * method has no effect. This will cause the install method to
1666:             * throw an IOException if the install is not writing the suite
1667:             * to storage which is the point of no return.
1668:             *
1669:             * @return true if the install will stop, false if it is too late
1670:             */
1671:            public boolean stopInstalling() {
1672:                if (state == null) {
1673:                    return false;
1674:                }
1675:
1676:                synchronized (state) {
1677:                    if (state.ignoreCancel) {
1678:                        return false;
1679:                    }
1680:
1681:                    state.stopInstallation = true;
1682:                }
1683:
1684:                return true;
1685:            }
1686:
1687:            /**
1688:             * Tells if the installation was stopped by another thread.
1689:             * @return true if the installation was stopped by another thread
1690:             */
1691:            public boolean wasStopped() {
1692:                if (state == null) {
1693:                    return false;
1694:                }
1695:
1696:                return state.stopInstallation;
1697:            }
1698:
1699:            /**
1700:             * Builds the initial API permission for suite currently being installed.
1701:             *
1702:             * @param domain security domain name for the CA of the suite
1703:             *
1704:             * @return current level of permissions
1705:             *
1706:             * @exception InvalidJadException if a permission attribute is not
1707:             *     formatted properly or a required permission is denied
1708:             */
1709:            protected byte[] getInitialPermissions(String domain)
1710:                    throws InvalidJadException {
1711:                byte[][] domainPermissions = Permissions.forDomain(domain);
1712:                byte[] permissions = Permissions.getEmptySet();
1713:
1714:                // only the current level of each permission has to be adjusted
1715:                getRequestedPermissions(MIDletSuite.PERMISSIONS_PROP,
1716:                        domainPermissions[Permissions.CUR_LEVELS], permissions,
1717:                        true);
1718:
1719:                getRequestedPermissions(MIDletSuite.PERMISSIONS_OPT_PROP,
1720:                        domainPermissions[Permissions.CUR_LEVELS], permissions,
1721:                        false);
1722:
1723:                return permissions;
1724:            }
1725:
1726:            /**
1727:             * Gets the permissions for a domain that are requested the manifest.
1728:             *
1729:             * @param propName name of the property in the manifest
1730:             * @param domainPermissions array of the starting levels for permissions
1731:             *        of a domain
1732:             * @param permissions array to put the permissions from the domain in
1733:             *        when found in the manifest property
1734:             * @param required if set to true the manifest permissions are required
1735:             *
1736:             * @exception InvalidJadException if a permission attribute is not
1737:             *     formatted properly or a required permission is denied
1738:             */
1739:            private void getRequestedPermissions(String propName,
1740:                    byte[] domainPermissions, byte[] permissions,
1741:                    boolean required) throws InvalidJadException {
1742:
1743:                String jadPermissionLine;
1744:                String reqPermissionLine;
1745:                Vector reqPermissions;
1746:                String permission;
1747:                boolean found;
1748:                int i;
1749:
1750:                reqPermissionLine = state.getAppProperty(propName);
1751:                if (reqPermissionLine == null
1752:                        || reqPermissionLine.length() == 0) {
1753:                    // Zero properties are allowed.
1754:                    return;
1755:                }
1756:
1757:                reqPermissions = Util
1758:                        .getCommaSeparatedValues(reqPermissionLine);
1759:                if (reqPermissions.size() == 0) {
1760:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
1761:                    throw new InvalidJadException(
1762:                            InvalidJadException.INVALID_VALUE);
1763:                }
1764:
1765:                for (int j = 0; j < reqPermissions.size(); j++) {
1766:                    permission = (String) reqPermissions.elementAt(j);
1767:
1768:                    if (permission.length() == 0) {
1769:                        postInstallMsgBackToProvider(OtaNotifier.INVALID_JAD_MSG);
1770:                        throw new InvalidJadException(
1771:                                InvalidJadException.INVALID_VALUE);
1772:                    }
1773:
1774:                    found = false;
1775:                    for (i = 0; i < Permissions.NUMBER_OF_PERMISSIONS; i++) {
1776:                        if (Permissions.getName(i).equals(permission)) {
1777:                            if (domainPermissions[i] != Permissions.NEVER) {
1778:                                found = true;
1779:                            }
1780:
1781:                            break;
1782:                        }
1783:                    }
1784:
1785:                    if (!found) {
1786:                        if (required) {
1787:                            postInstallMsgBackToProvider(OtaNotifier.AUTHORIZATION_FAILURE_MSG);
1788:                            throw new InvalidJadException(
1789:                                    InvalidJadException.AUTHORIZATION_FAILURE,
1790:                                    permission);
1791:                        }
1792:
1793:                        continue;
1794:                    }
1795:
1796:                    permissions[i] = domainPermissions[i];
1797:                }
1798:            }
1799:
1800:            /**
1801:             * Apply the previous user level permission of the currently installed
1802:             * version of a suite to the next version of the suite in a secure way.
1803:             *
1804:             * @param current array permissions for the current version
1805:             * @param domainPermissions array of the starting levels for permissions
1806:             *        of the new domain
1807:             * @param next array permissions for the next version
1808:             */
1809:            private void applyCurrentUserLevelPermissions(byte[] current,
1810:                    byte[] domainPermissions, byte[] next) {
1811:
1812:                for (int i = 0; i < current.length && i < next.length; i++) {
1813:                    switch (current[i]) {
1814:                    case Permissions.ALLOW:
1815:                    case Permissions.NEVER:
1816:                        // not a user level permission
1817:                        continue;
1818:                    }
1819:
1820:                    switch (domainPermissions[i]) {
1821:                    case Permissions.ALLOW:
1822:                    case Permissions.NEVER:
1823:                        // not a user level permission
1824:                        continue;
1825:
1826:                    case Permissions.ONESHOT:
1827:                        if (current[i] == Permissions.SESSION) {
1828:                            // do not apply
1829:                            continue;
1830:                        }
1831:                        // fall through; per-session permissions may be permitted.
1832:
1833:                    case Permissions.SESSION:
1834:                        if (current[i] == Permissions.BLANKET
1835:                                || current[i] == Permissions.BLANKET_GRANTED) {
1836:                            // do not apply
1837:                            continue;
1838:                        }
1839:                        // fall through to store the permission for the next version.
1840:
1841:                    default:
1842:                        next[i] = current[i];
1843:                        continue;
1844:                    }
1845:                }
1846:            }
1847:
1848:            /**
1849:             * Checks to see if the JAD has a signature, but does not verify the
1850:             * signature. This is a place holder the the Secure Installer and
1851:             * just returns false.
1852:             *
1853:             * @return true if the JAD has a signature
1854:             */
1855:            public boolean isJadSigned() {
1856:                return verifier.isJadSigned();
1857:            }
1858:
1859:            /**
1860:             * Checks if the calling suite has Permissions.MIDP permission.
1861:             * If not, the SecurityException is thrown.
1862:             */
1863:            private void checkMidpPermission() {
1864:                MIDletSuite midletSuite = MIDletStateHandler
1865:                        .getMidletStateHandler().getMIDletSuite();
1866:
1867:                // if a MIDlet suite is not started, assume the JAM is calling.
1868:                if (midletSuite != null) {
1869:                    midletSuite.checkIfPermissionAllowed(Permissions.MIDP);
1870:                }
1871:            }
1872:
1873:            /**
1874:             * Sets security domain for unsigned suites. The default is untrusted.
1875:             * Can only be called by JAM for testing.
1876:             *
1877:             * @param domain name of a security domain
1878:             * @param allowedPermissions list of permissions that must be allowed even
1879:             * if they are absent from the jad file; "all" to allow all permissions
1880:             */
1881:            public void setUnsignedSecurityDomain(String domain) {
1882:                checkMidpPermission();
1883:                unsignedSecurityDomain = domain;
1884:            }
1885:
1886:            /**
1887:             * Sets the permissions that must be allowed not depending on their
1888:             * presence in the application descriptor file.
1889:             * Can only be called by JAM for testing.
1890:             *
1891:             * @param extraPermissions list of permissions that must be allowed even
1892:             * if they are absent from the jad file; "all" to allow all permissions
1893:             */
1894:            public void setExtraPermissions(String extraPermissions) {
1895:                checkMidpPermission();
1896:                additionalPermissions = extraPermissions;
1897:            }
1898:
1899:            /**
1900:             * Checks to see that if any properties that are both in the JAD and
1901:             * JAR manifest are not equal and throw a exception and notify the
1902:             * server when a mismatch is found. Only used for trusted suites.
1903:             * @exception InvalidJadException  if the properties do not match
1904:             */
1905:            protected void checkForJadManifestMismatches()
1906:                    throws InvalidJadException {
1907:
1908:                for (int i = 0; i < state.jarProps.size(); i++) {
1909:                    String key = state.jarProps.getKeyAt(i);
1910:                    String value = state.jarProps.getValueAt(i);
1911:                    String dup = state.jadProps.getProperty(key);
1912:
1913:                    if (dup == null) {
1914:                        continue;
1915:                    }
1916:
1917:                    if (!dup.equals(value)) {
1918:                        postInstallMsgBackToProvider(OtaNotifier.ATTRIBUTE_MISMATCH_MSG);
1919:                        throw new InvalidJadException(
1920:                                InvalidJadException.ATTRIBUTE_MISMATCH, key);
1921:                    }
1922:                }
1923:            }
1924:
1925:            /**
1926:             * Compares two version strings. The return values are very similar to
1927:             * that of strcmp() in 'C'. If the first version is less than the second
1928:             * version, a negative number will be returned. If the first version is
1929:             * greater than the second version, a positive number will be returned.
1930:             * If the two versions are equal, zero is returned.
1931:             * <p>
1932:             * Versions must be in the form <em>xxx.yyy.zzz</em>, where:
1933:             * <pre>
1934:             *     <em>xxx</em> is the major version
1935:             *     <em>yyy</em> is the minor version
1936:             *     <em>zzz</em> is the micro version
1937:             * </pre>
1938:             * It is acceptable to omit the micro and possibly the minor versions.
1939:             * If these are not included in the version string, the period immediately
1940:             * preceding the number must also be removed. So, the versions
1941:             * <em>xxx.yyy</em> or <em>xxx</em> are also valid.
1942:             * <p>
1943:             * Version numbers do not have to be three digits wide. However, you may
1944:             * pad versions with leading zeros if desired.
1945:             * <p>
1946:             * If a version number is omitted, its value is assumed to be zero. All
1947:             * tests will be based on this assumption.
1948:             * <p>
1949:             * For example:
1950:             * <pre>
1951:             *    1.04  >  1.
1952:             *    1.04  <  1.4.1
1953:             *    1.04  =  1.4.0
1954:             * </pre>
1955:             * <p>
1956:             *
1957:             * @param ver1 the first version to compare
1958:             * @param ver2 the second version to compare
1959:             *
1960:             * @return  1 if <code>ver1</code> is greater than <code>ver2</code>
1961:             *          0 if <code>ver1</code> is equal to <code>ver2</code>
1962:             *         -1 if <code>ver1</code> is less than <code>ver2</code>
1963:             *
1964:             * @exception NumberFormatException if either <code>ver1</code> or
1965:             * <code>ver2</code> contain characters that are not numbers or periods
1966:             */
1967:            private static int vercmp(String ver1, String ver2)
1968:                    throws NumberFormatException {
1969:                String strVal1;
1970:                String strVal2;
1971:                int intVal1;
1972:                int intVal2;
1973:                int idx1 = 0;
1974:                int idx2 = 0;
1975:                int newidx;
1976:
1977:                if ((ver1 == null) && (ver2 == null)) {
1978:                    return 0;
1979:                }
1980:
1981:                if (ver1 == null) {
1982:                    return -1;
1983:                }
1984:
1985:                if (ver2 == null) {
1986:                    return 1;
1987:                }
1988:
1989:                for (int i = 0; i < 3; i++) {
1990:                    strVal1 = "0"; // Default value
1991:                    strVal2 = "0"; // Default value
1992:                    if (idx1 >= 0) {
1993:                        newidx = ver1.indexOf('.', idx1);
1994:                        if (newidx < 0) {
1995:                            strVal1 = ver1.substring(idx1);
1996:                        } else {
1997:                            strVal1 = ver1.substring(idx1, newidx);
1998:                            newidx++; // Idx of '.'; need to go to next char
1999:                        }
2000:
2001:                        idx1 = newidx;
2002:                    }
2003:
2004:                    if (idx2 >= 0) {
2005:                        newidx = ver2.indexOf('.', idx2);
2006:                        if (newidx < 0) {
2007:                            strVal2 = ver2.substring(idx2);
2008:                        } else {
2009:                            strVal2 = ver2.substring(idx2, newidx);
2010:                            newidx++;
2011:                        }
2012:
2013:                        idx2 = newidx;
2014:                    }
2015:
2016:                    intVal1 = Integer.parseInt(strVal1); // May throw NFE
2017:                    intVal2 = Integer.parseInt(strVal2); // May throw NFE
2018:
2019:                    if (intVal1 > intVal2) {
2020:                        return 1;
2021:                    }
2022:
2023:                    if (intVal1 < intVal2) {
2024:                        return -1;
2025:                    }
2026:                }
2027:
2028:                return 0;
2029:            }
2030:
2031:            /**
2032:             * Checks the format of a version string.
2033:             * <p>
2034:             * Versions must be in the form <em>xxx.yyy.zzz</em>, where:
2035:             * <pre>
2036:             *     <em>xxx</em> is the major version
2037:             *     <em>yyy</em> is the minor version
2038:             *     <em>zzz</em> is the micro version
2039:             * </pre>
2040:             * It is acceptable to omit the micro and possibly the minor versions.
2041:             * If these are not included in the version string, the period immediately
2042:             * preceding the number must also be removed. So, the versions
2043:             * <em>xxx.yyy</em> or <em>xxx</em> are also valid.
2044:             * <p>
2045:             * Version numbers do not have to be three digits wide. However, you may
2046:             * pad versions with leading zeros if desired.
2047:             *
2048:             * @param ver the version to check
2049:             *
2050:             * @exception NumberFormatException if <code>ver</code>
2051:             *     contains any characters that are not numbers or periods
2052:             */
2053:            private static void checkVersionFormat(String ver)
2054:                    throws NumberFormatException {
2055:                int length;
2056:                int start = 0;
2057:                int end;
2058:
2059:                length = ver.length();
2060:                for (int i = 0;; i++) {
2061:                    // check for more than 3 parts or a trailing '.'
2062:                    if (i == 3 || start == length) {
2063:                        throw new NumberFormatException();
2064:                    }
2065:
2066:                    end = ver.indexOf('.', start);
2067:                    if (end == -1) {
2068:                        end = length;
2069:                    }
2070:
2071:                    // throws NFE if the substring is not all digits
2072:                    Integer.parseInt(ver.substring(start, end));
2073:
2074:                    if (end == length) {
2075:                        // we are done
2076:                        return;
2077:                    }
2078:
2079:                    // next time around start after the index of '.'
2080:                    start = end + 1;
2081:                }
2082:            }
2083:
2084:            /**
2085:             * Checks to make sure the runtime environment required by
2086:             * the application is supported.
2087:             * Send a message back to the server if the check fails and
2088:             * throw an exception.
2089:             *
2090:             * @exception InvalidJadException if the check fails
2091:             */
2092:            private void checkRuntimeEnv() throws InvalidJadException {
2093:                String execEnv;
2094:
2095:                execEnv = state
2096:                        .getAppProperty(MIDletSuite.RUNTIME_EXEC_ENV_PROP);
2097:                if (execEnv == null || execEnv.length() == 0) {
2098:                    execEnv = MIDletSuite.RUNTIME_EXEC_ENV_DEFAULT;
2099:                }
2100:
2101:                // need to call trim to remove trailing spaces
2102:                execEnv = execEnv.trim();
2103:
2104:                if (execEnv.equals(cldcRuntimeEnv)) {
2105:                    // success, done
2106:                    return;
2107:                }
2108:
2109:                postInstallMsgBackToProvider(OtaNotifier.INCOMPATIBLE_MSG);
2110:                throw new InvalidJadException(
2111:                        InvalidJadException.DEVICE_INCOMPATIBLE);
2112:            }
2113:
2114:            /**
2115:             * Match the name of the configuration or profile, and return
2116:             * true if the first name has a greater or equal version than the
2117:             * second. The names of the format "XXX-Y.Y" (e.g. CLDC-1.0, MIDP-2.0)
2118:             * as used in the system properties (microedition.configuration &
2119:             * microedition.profiles).
2120:             *
2121:             * This is used for checking both configuration and profiles.
2122:             *
2123:             * @param name1 name of configuration or profile
2124:             * @param name2 name of configuration or profile
2125:             * @return  true is name1 matches name2 and is greater or equal in
2126:             *          version number. false otherwise
2127:             */
2128:            private static boolean matchVersion(String name1, String name2) {
2129:                int dash1 = name1.indexOf('-');
2130:
2131:                if (dash1 < 0) {
2132:                    return false;
2133:                }
2134:
2135:                int dash2 = name2.indexOf('-');
2136:
2137:                if (dash2 < 0) {
2138:                    return false;
2139:                }
2140:
2141:                String base1 = name1.substring(0, dash1);
2142:                String base2 = name2.substring(0, dash2);
2143:
2144:                if (!base1.equals(base2)) {
2145:                    return false;
2146:                }
2147:
2148:                String ver1 = name1.substring(dash1 + 1, name1.length());
2149:                String ver2 = name2.substring(dash2 + 1, name2.length());
2150:
2151:                return (vercmp(ver1, ver2) >= 0);
2152:            }
2153:
2154:            /**
2155:             * Checks to make sure the configration need by the application
2156:             * is supported.
2157:             * Send a message back to the server if the check fails and
2158:             * throw an exception.
2159:             *
2160:             * @exception InvalidJadException if the check fails
2161:             */
2162:            private void checkConfiguration() throws InvalidJadException {
2163:                String config;
2164:
2165:                config = state.getAppProperty(MIDletSuite.CONFIGURATION_PROP);
2166:                if (config == null || config.length() == 0) {
2167:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAR_MSG);
2168:                    throw new InvalidJadException(
2169:                            InvalidJadException.MISSING_CONFIGURATION);
2170:                }
2171:
2172:                if (cldcConfig == null) {
2173:                    // need to call trim to remove trailing spaces
2174:                    cldcConfig = System.getProperty(MICROEDITION_CONFIG).trim();
2175:                }
2176:
2177:                if (matchVersion(cldcConfig, config)) {
2178:                    // success, done
2179:                    return;
2180:                }
2181:
2182:                postInstallMsgBackToProvider(OtaNotifier.INCOMPATIBLE_MSG);
2183:                throw new InvalidJadException(
2184:                        InvalidJadException.DEVICE_INCOMPATIBLE);
2185:            }
2186:
2187:            /**
2188:             * Tries to match one of the supported profiles with a profile
2189:             * listed in string of profiles separated by a space.
2190:             * Send a message back to the server if a match is not found and
2191:             * throw an exception.
2192:             *
2193:             * @exception InvalidJadException if there is no match
2194:             */
2195:            private void matchProfile() throws InvalidJadException {
2196:                String profiles = state
2197:                        .getAppProperty(MIDletSuite.PROFILE_PROP);
2198:
2199:                if (profiles == null || profiles.length() == 0) {
2200:                    postInstallMsgBackToProvider(OtaNotifier.INVALID_JAR_MSG);
2201:                    throw new InvalidJadException(
2202:                            InvalidJadException.MISSING_PROFILE);
2203:                }
2204:
2205:                // build the list of supported profiles if needed
2206:                if (supportedProfiles == null) {
2207:                    int start;
2208:                    int nextSpace = -1;
2209:                    String meProfiles = System
2210:                            .getProperty(MICROEDITION_PROFILES);
2211:                    if (meProfiles == null || meProfiles.length() == 0) {
2212:                        throw new RuntimeException(
2213:                                "system property microedition.profiles not set");
2214:                    }
2215:                    supportedProfiles = new Vector();
2216:                    // need to call trim to remove trailing spaces
2217:                    meProfiles = meProfiles.trim();
2218:
2219:                    for (;;) {
2220:                        start = nextSpace + 1;
2221:                        nextSpace = meProfiles.indexOf(' ', start);
2222:
2223:                        // consecutive spaces, keep searching
2224:                        if (nextSpace == start) {
2225:                            continue;
2226:                        }
2227:
2228:                        if ((nextSpace < 0)) {
2229:                            supportedProfiles.addElement(meProfiles.substring(
2230:                                    start, meProfiles.length()));
2231:                            break;
2232:                        }
2233:
2234:                        supportedProfiles.addElement(meProfiles.substring(
2235:                                start, nextSpace));
2236:
2237:                    }
2238:                }
2239:
2240:                /*
2241:                 * for each profiles listed in MicroEdition-Profile, we need to
2242:                 * find a matching profile in microedition.profiles.
2243:                 */
2244:                int current = 0;
2245:                int nextSeparatorIndex = 0;
2246:                String requestedProfile;
2247:                boolean supported = false;
2248:
2249:                // convert tab to space so that the parsing later is simplified
2250:                StringBuffer tmp = new StringBuffer(profiles);
2251:                boolean modified = false;
2252:                while ((nextSeparatorIndex = profiles.indexOf('\t', current)) != -1) {
2253:                    tmp.setCharAt(nextSeparatorIndex, ' ');
2254:                    current++;
2255:                    modified = true;
2256:                }
2257:
2258:                if (modified) {
2259:                    profiles = tmp.toString();
2260:                }
2261:
2262:                // reset the indices
2263:                current = nextSeparatorIndex = 0;
2264:                do {
2265:                    // get the next requested profiles
2266:                    nextSeparatorIndex = profiles.indexOf(' ', current);
2267:
2268:                    if (nextSeparatorIndex == current) {
2269:                        // consecutive spaces, keep searching
2270:                        current++;
2271:                        continue;
2272:                    }
2273:
2274:                    if (nextSeparatorIndex == -1) {
2275:                        // last (or the only one) value in the list
2276:                        requestedProfile = profiles.substring(current, profiles
2277:                                .length());
2278:                    } else {
2279:                        requestedProfile = profiles.substring(current,
2280:                                nextSeparatorIndex);
2281:                        current = nextSeparatorIndex + 1;
2282:                    }
2283:
2284:                    /*
2285:                     * try to match each requested profiles against the supported
2286:                     * ones.
2287:                     */
2288:                    supported = false;
2289:                    for (int i = 0; i < supportedProfiles.size(); i++) {
2290:                        String supportedProfile = (String) supportedProfiles
2291:                                .elementAt(i);
2292:                        if (matchVersion(supportedProfile, requestedProfile)) {
2293:                            supported = true;
2294:                            break;
2295:                        }
2296:                    }
2297:
2298:                    // short circuit the test if there is one mismatch
2299:                    if (!supported) {
2300:                        break;
2301:                    }
2302:                } while (nextSeparatorIndex != -1);
2303:
2304:                // matched all requested profiles against supported ones
2305:                if (supported) {
2306:                    return;
2307:                }
2308:
2309:                postInstallMsgBackToProvider(OtaNotifier.INCOMPATIBLE_MSG);
2310:                throw new InvalidJadException(
2311:                        InvalidJadException.DEVICE_INCOMPATIBLE);
2312:            }
2313:
2314:            /**
2315:             * Registers the push connections for the application.
2316:             * Send a message back to the server if a connection cannot be
2317:             * registered and throw an exception.
2318:             *
2319:             * @exception InvalidJadException if a connection cannot be registered
2320:             */
2321:            private void registerPushConnections() throws InvalidJadException {
2322:                byte[] curLevels = settings.getPermissions();
2323:
2324:                if (state.isPreviousVersion) {
2325:                    PushRegistryInternal.unregisterConnections(info.id);
2326:                }
2327:
2328:                for (int i = 1;; i++) {
2329:                    String pushProp;
2330:
2331:                    pushProp = state.getAppProperty("MIDlet-Push-" + i);
2332:                    if (pushProp == null) {
2333:                        break;
2334:                    }
2335:
2336:                    /*
2337:                     * Parse the comma separated values  -
2338:                     *  " connection, midlet, role, filter"
2339:                     */
2340:                    int comma1 = pushProp.indexOf(',', 0);
2341:                    int comma2 = pushProp.indexOf(',', comma1 + 1);
2342:
2343:                    String conn = pushProp.substring(0, comma1).trim();
2344:                    String midlet = pushProp.substring(comma1 + 1, comma2)
2345:                            .trim();
2346:                    String filter = pushProp.substring(comma2 + 1).trim();
2347:
2348:                    /* Register the new push connection string. */
2349:                    try {
2350:                        PushRegistryInternal.registerConnectionInternal(state,
2351:                                conn, midlet, filter, false);
2352:                    } catch (Exception e) {
2353:                        /* If already registered, abort the installation. */
2354:                        PushRegistryInternal.unregisterConnections(info.id);
2355:
2356:                        if (state.isPreviousVersion) {
2357:                            // put back the old ones, removed above
2358:                            redoPreviousPushConnections();
2359:                        }
2360:
2361:                        if (e instanceof  SecurityException) {
2362:                            postInstallMsgBackToProvider(OtaNotifier.AUTHORIZATION_FAILURE_MSG);
2363:
2364:                            // since our state object put the permission in message
2365:                            throw new InvalidJadException(
2366:                                    InvalidJadException.AUTHORIZATION_FAILURE,
2367:                                    e.getMessage());
2368:                        }
2369:
2370:                        postInstallMsgBackToProvider(OtaNotifier.PUSH_REG_FAILURE_MSG);
2371:
2372:                        if (e instanceof  IllegalArgumentException) {
2373:                            throw new InvalidJadException(
2374:                                    InvalidJadException.PUSH_FORMAT_FAILURE,
2375:                                    pushProp);
2376:                        }
2377:
2378:                        if (e instanceof  ConnectionNotFoundException) {
2379:                            throw new InvalidJadException(
2380:                                    InvalidJadException.PUSH_PROTO_FAILURE,
2381:                                    pushProp);
2382:                        }
2383:
2384:                        if (e instanceof  IOException) {
2385:                            throw new InvalidJadException(
2386:                                    InvalidJadException.PUSH_DUP_FAILURE,
2387:                                    pushProp);
2388:                        }
2389:
2390:                        if (e instanceof  ClassNotFoundException) {
2391:                            throw new InvalidJadException(
2392:                                    InvalidJadException.PUSH_CLASS_FAILURE,
2393:                                    pushProp);
2394:                        }
2395:
2396:                        // error in the implementation code
2397:                        throw (RuntimeException) e;
2398:                    }
2399:                }
2400:
2401:                if (state.isPreviousVersion) {
2402:                    // preserve the push options when updating
2403:                    settings.setPushOptions(state.previousSuite
2404:                            .getPushOptions());
2405:
2406:                    // use the old setting
2407:                    settings.setPushInterruptSetting((byte) state.previousSuite
2408:                            .getPushInterruptSetting());
2409:
2410:                    // The old suite may have not had push connections
2411:                    if (settings.getPushInterruptSetting() != Permissions.NEVER) {
2412:                        return;
2413:                    }
2414:                }
2415:
2416:                if (curLevels[Permissions.PUSH] == Permissions.NEVER) {
2417:                    settings.setPushInterruptSetting(Permissions.NEVER);
2418:                } else if (curLevels[Permissions.PUSH] == Permissions.ALLOW) {
2419:                    // Start the default at session for usability when denying.
2420:                    settings.setPushInterruptSetting(Permissions.SESSION);
2421:                } else {
2422:                    settings
2423:                            .setPushInterruptSetting(curLevels[Permissions.PUSH]);
2424:                }
2425:            }
2426:
2427:            /**
2428:             * Registers the push connections for previous version after
2429:             * and aborted update.
2430:             */
2431:            private void redoPreviousPushConnections() {
2432:                for (int i = 1;; i++) {
2433:                    String pushProp;
2434:
2435:                    pushProp = state.previousSuite.getProperty("MIDlet-Push-"
2436:                            + i);
2437:                    if (pushProp == null) {
2438:                        break;
2439:                    }
2440:
2441:                    /*
2442:                     * Parse the comma separated values  -
2443:                     *  " connection, midlet, role, filter"
2444:                     */
2445:                    int comma1 = pushProp.indexOf(',', 0);
2446:                    int comma2 = pushProp.indexOf(',', comma1 + 1);
2447:
2448:                    String conn = pushProp.substring(0, comma1).trim();
2449:                    String midlet = pushProp.substring(comma1 + 1, comma2)
2450:                            .trim();
2451:                    String filter = pushProp.substring(comma2 + 1).trim();
2452:
2453:                    /* Register the new push connection string. */
2454:                    try {
2455:                        PushRegistryInternal.registerConnectionInternal(state,
2456:                                conn, midlet, filter, true);
2457:                    } catch (IOException e) {
2458:                        if (Logging.REPORT_LEVEL <= Logging.WARNING) {
2459:                            Logging
2460:                                    .report(Logging.WARNING,
2461:                                            LogChannels.LC_AMS,
2462:                                            "registerConnectionInternal  threw an IOException");
2463:                        }
2464:                    } catch (ClassNotFoundException e) {
2465:                        if (Logging.REPORT_LEVEL <= Logging.WARNING) {
2466:                            Logging.report(Logging.WARNING, LogChannels.LC_AMS,
2467:                                    "registerConnectionInternal threw a "
2468:                                            + "ClassNotFoundException");
2469:                        }
2470:                    }
2471:                }
2472:            }
2473:        }
2474:
2475:        /**
2476:         * Holds the state of an installation, so it can restarted after it has
2477:         * been stopped.
2478:         */
2479:        class InstallStateImpl implements  InstallState, MIDletSuite {
2480:            /** Contains the data obtained during the installation process */
2481:            protected InstallInfo installInfo;
2482:
2483:            /** Contains the data obtained during the installation process */
2484:            protected SuiteSettings suiteSettings;
2485:
2486:            /** ID of the storage where the new midlet suite will be installed. */
2487:            protected int storageId;
2488:
2489:            /** Receives warnings and status. */
2490:            protected InstallListener listener;
2491:
2492:            /** When the install started, in milliseconds. */
2493:            protected long startTime;
2494:
2495:            /** What to do next. */
2496:            protected int nextStep;
2497:
2498:            /** Signals the installation to stop. */
2499:            protected boolean stopInstallation;
2500:
2501:            /**
2502:             * Signals that installation is at a point where cancel
2503:             * requests are ignored
2504:             */
2505:            protected boolean ignoreCancel;
2506:
2507:            /** exception that stopped the installation. */
2508:            protected InvalidJadException exception;
2509:
2510:            /**
2511:             * Option to force an overwrite of existing components without
2512:             * any version comparison.
2513:             */
2514:            protected boolean force;
2515:
2516:            /**
2517:             * Option to force the RMS data of the suite to be overwritten to
2518:             * be removed without comparison to the new suite.
2519:             */
2520:            protected boolean removeRMS;
2521:
2522:            /** Raw JAD. */
2523:            protected byte[] jad;
2524:
2525:            /** character encoding of the JAD. */
2526:            protected String jadEncoding;
2527:
2528:            /** Parsed JAD. */
2529:            protected JadProperties jadProps;
2530:
2531:            /** Parsed manifest. */
2532:            protected ManifestProperties jarProps;
2533:
2534:            /** Cached File object. */
2535:            protected File file;
2536:
2537:            /** User name for authentication. */
2538:            protected String username;
2539:
2540:            /** Password for authentication. */
2541:            protected String password;
2542:
2543:            /** User name for proxyAuthentication. */
2544:            protected String proxyUsername;
2545:
2546:            /** Password for proxy authentication. */
2547:            protected String proxyPassword;
2548:
2549:            /** Status to signal the beginning of the data transfer. */
2550:            protected int beginTransferDataStatus;
2551:
2552:            /** Status for the data transfer method to give to the listener. */
2553:            protected int transferStatus;
2554:
2555:            /** Security Handler. */
2556:            protected SecurityHandler securityHandler;
2557:
2558:            /** Holds the unzipped JAR manifest to be saved. */
2559:            protected byte[] manifest;
2560:
2561:            /** Cache of storage object. */
2562:            protected RandomAccessStream storage;
2563:
2564:            /** Cache of MIDlet suite storage object. */
2565:            protected MIDletSuiteStorage midletSuiteStorage;
2566:
2567:            /** The root of all MIDP persistent system data. */
2568:            protected String storageRoot;
2569:
2570:            /** Signals that previous version exists. */
2571:            protected boolean isPreviousVersion;
2572:
2573:            /** Previous MIDlet suite info. */
2574:            protected MIDletSuiteImpl previousSuite;
2575:
2576:            /** Previous MIDlet suite install info. */
2577:            protected InstallInfo previousInstallInfo;
2578:
2579:            /** The ContentHandler installer state. */
2580:            protected CHManager chmanager;
2581:
2582:            /** Constructor. */
2583:            public InstallStateImpl() {
2584:                installInfo = new InstallInfo(UNUSED_SUITE_ID);
2585:                suiteSettings = new SuiteSettings(UNUSED_SUITE_ID);
2586:            }
2587:
2588:            /**
2589:             * Gets the last recoverable exception that stopped the install.
2590:             * Non-recoverable exceptions are thrown and not saved in the state.
2591:             *
2592:             * @return last exception that stopped the install
2593:             */
2594:            public InvalidJadException getLastException() {
2595:                return exception;
2596:            }
2597:
2598:            /**
2599:             * Gets the unique ID that the installed suite was stored with.
2600:             *
2601:             * @return storage name that can be used to load the suite
2602:             */
2603:            public int getID() {
2604:                return installInfo.id;
2605:            }
2606:
2607:            /**
2608:             * Sets the username to be used for HTTP authentication.
2609:             *
2610:             * @param theUsername 8 bit username, cannot contain a ":"
2611:             */
2612:            public void setUsername(String theUsername) {
2613:                username = theUsername;
2614:            }
2615:
2616:            /**
2617:             * Sets the password to be used for HTTP authentication.
2618:             *
2619:             * @param thePassword 8 bit password
2620:             */
2621:            public void setPassword(String thePassword) {
2622:                password = thePassword;
2623:            }
2624:
2625:            /**
2626:             * Sets the username to be used for HTTP proxy authentication.
2627:             *
2628:             * @param theUsername 8 bit username, cannot contain a ":"
2629:             */
2630:            public void setProxyUsername(String theUsername) {
2631:                proxyUsername = theUsername;
2632:            }
2633:
2634:            /**
2635:             * Sets the password to be used for HTTP proxy authentication.
2636:             *
2637:             * @param thePassword 8 bit password
2638:             */
2639:            public void setProxyPassword(String thePassword) {
2640:                proxyPassword = thePassword;
2641:            }
2642:
2643:            /**
2644:             * Gets a property of the application to be installed.
2645:             * First from the JAD, then if not found, the JAR manifest.
2646:             *
2647:             * @param key key of the property
2648:             *
2649:             * @return value of the property or null if not found
2650:             */
2651:            public String getAppProperty(String key) {
2652:                String value;
2653:
2654:                if (jadProps != null) {
2655:                    value = jadProps.getProperty(key);
2656:                    if (value != null) {
2657:                        return value;
2658:                    }
2659:                }
2660:
2661:                if (jarProps != null) {
2662:                    value = jarProps.getProperty(key);
2663:                    if (value != null) {
2664:                        return value;
2665:                    }
2666:                }
2667:
2668:                return null;
2669:            }
2670:
2671:            /**
2672:             * Gets the URL of the JAR.
2673:             *
2674:             * @return URL of the JAR
2675:             */
2676:            public String getJarUrl() {
2677:                return installInfo.jarUrl;
2678:            }
2679:
2680:            /**
2681:             * Gets the label for the downloaded JAR.
2682:             *
2683:             * @return suite name
2684:             */
2685:            public String getSuiteName() {
2686:                return installInfo.suiteName;
2687:            }
2688:
2689:            /**
2690:             * Gets the expected size of the JAR.
2691:             *
2692:             * @return size of the JAR in K bytes rounded up
2693:             */
2694:            public int getJarSize() {
2695:                return (installInfo.expectedJarSize + 1023) / 1024;
2696:            }
2697:
2698:            /**
2699:             * Gets the authorization path of this suite. The path starts with
2700:             * the most trusted CA that authorized this suite.
2701:             *
2702:             * @return array of CA names or null if the suite was not signed
2703:             */
2704:            public String[] getAuthPath() {
2705:                /*
2706:                 * The auth path returned is no a copy because this object is
2707:                 * only available to callers with the AMS permission, which
2708:                 * have permission to build auth paths for new suites.
2709:                 */
2710:                return installInfo.getAuthPath();
2711:            }
2712:
2713:            /**
2714:             * Checks for permission and throw an exception if not allowed.
2715:             * May block to ask the user a question.
2716:             *
2717:             * @param permission ID of the permission to check for,
2718:             *      the ID must be from
2719:             *      {@link com.sun.midp.security.Permissions}
2720:             * @param resource string to insert into the question, can be null if
2721:             *        no %2 in the question
2722:             *
2723:             * @exception SecurityException if the permission is not
2724:             *            allowed by this token
2725:             * @exception InterruptedException if another thread interrupts the
2726:             *   calling thread while this method is waiting to preempt the
2727:             *   display.
2728:             */
2729:            public void checkForPermission(int permission, String resource)
2730:                    throws InterruptedException {
2731:                checkForPermission(permission, resource, null);
2732:            }
2733:
2734:            /**
2735:             * Checks for permission and throw an exception if not allowed.
2736:             * May block to ask the user a question.
2737:             *
2738:             * @param permission ID of the permission to check for,
2739:             *      the ID must be from
2740:             *      {@link com.sun.midp.security.Permissions}
2741:             * @param resource string to insert into the question, can be null if
2742:             *        no %2 in the question
2743:             * @param extraValue string to insert into the question,
2744:             *        can be null if no %3 in the question
2745:             *
2746:             * @exception SecurityException if the permission is not
2747:             *            allowed by this token
2748:             * @exception InterruptedException if another thread interrupts the
2749:             *   calling thread while this method is waiting to preempt the
2750:             *   display.
2751:             */
2752:            public void checkForPermission(int permission, String resource,
2753:                    String extraValue) throws InterruptedException {
2754:
2755:                securityHandler.checkForPermission(permission, Permissions
2756:                        .getTitle(permission), Permissions
2757:                        .getQuestion(permission), Permissions
2758:                        .getOneshotQuestion(permission), installInfo.suiteName,
2759:                        resource, extraValue, Permissions.getName(permission));
2760:            }
2761:
2762:            /**
2763:             * Indicates if the named MIDlet is registered in the suite
2764:             * with MIDlet-&lt;n&gt; record in the manifest or
2765:             * application descriptor.
2766:             * @param midletName class name of the MIDlet to be checked
2767:             *
2768:             * @return true if the MIDlet is registered
2769:             */
2770:            public boolean isRegistered(String midletName) {
2771:                String midlet;
2772:                MIDletInfo midletInfo;
2773:
2774:                for (int i = 1;; i++) {
2775:                    midlet = getAppProperty("MIDlet-" + i);
2776:                    if (midlet == null) {
2777:                        return false; // We went past the last MIDlet
2778:                    }
2779:
2780:                    /* Check if the names match. */
2781:                    midletInfo = new MIDletInfo(midlet);
2782:                    if (midletInfo.classname.equals(midletName)) {
2783:                        return true;
2784:                    }
2785:                }
2786:            }
2787:
2788:            /**
2789:             * Counts the number of MIDlets from its properties.
2790:             * IMPL_NOTE: refactor to avoid duplication with MIDletSuiteImpl.
2791:             *
2792:             * @return number of midlet in the suite
2793:             */
2794:            public int getNumberOfMIDlets() {
2795:                int i;
2796:
2797:                for (i = 1; getProperty("MIDlet-" + i) != null; i++)
2798:                    ;
2799:
2800:                return (i - 1);
2801:            }
2802:
2803:            /**
2804:             * Returns the suite's name to display to the user.
2805:             *
2806:             * @return suite's name that will be displayed to the user
2807:             */
2808:            public String getDisplayName() {
2809:                String displayName = getAppProperty(MIDletSuite.SUITE_NAME_PROP);
2810:
2811:                if (displayName == null) {
2812:                    displayName = String.valueOf(installInfo.id);
2813:                }
2814:
2815:                return displayName;
2816:            }
2817:
2818:            /**
2819:             * Returns the information about the first midlet in the suite.
2820:             *
2821:             * @return MIDletInfo structure describing the first midlet
2822:             * or null if it is not available
2823:             */
2824:            public MIDletInfo getMidletInfo() {
2825:                String midlet;
2826:
2827:                midlet = getAppProperty("MIDlet-1");
2828:                if (midlet == null) {
2829:                    return null;
2830:                }
2831:
2832:                return new MIDletInfo(midlet);
2833:            }
2834:
2835:            /**
2836:             * Indicates if this suite is trusted.
2837:             * (not to be confused with a domain named "trusted",
2838:             * this is used to determine if a trusted symbol should be displayed
2839:             * to the user and not used for permissions)
2840:             *
2841:             * @return true if the suite is trusted false if not
2842:             */
2843:            public boolean isTrusted() {
2844:                return installInfo.trusted;
2845:            }
2846:
2847:            /**
2848:             * Check if the suite classes were successfully verified
2849:             * during the suite installation.
2850:             *
2851:             * @return true if the suite classes are verified, false otherwise
2852:             */
2853:            public boolean isVerified() {
2854:                return installInfo.verifyHash != null;
2855:            }
2856:
2857:            /**
2858:             * Gets a property of the suite. A property is an attribute from
2859:             * either the application descriptor or JAR Manifest.
2860:             *
2861:             * @param key the name of the property
2862:             * @return A string with the value of the property.
2863:             *    <code>null</code> is returned if no value
2864:             *          is available for the key.
2865:             */
2866:            public String getProperty(String key) {
2867:                return getAppProperty(key);
2868:            }
2869:
2870:            /**
2871:             * Gets push setting for interrupting other MIDlets.
2872:             * Reuses the Permissions.
2873:             *
2874:             * @return push setting for interrupting MIDlets the value
2875:             *        will be permission level from {@link Permissions}
2876:             */
2877:            public byte getPushInterruptSetting() {
2878:                return suiteSettings.getPushInterruptSetting();
2879:            }
2880:
2881:            /**
2882:             * Gets push options for this suite.
2883:             *
2884:             * @return push options are defined in {@link PushRegistryImpl}
2885:             */
2886:            public int getPushOptions() {
2887:                return suiteSettings.getPushOptions();
2888:            }
2889:
2890:            /**
2891:             * Gets list of permissions for this suite.
2892:             *
2893:             * @return array of permissions from {@link Permissions}
2894:             */
2895:            public byte[] getPermissions() {
2896:                return suiteSettings.getPermissions();
2897:            }
2898:
2899:            /**
2900:             * Replace or add a property to the suite for this run only.
2901:             *
2902:             * @param token token with the AMS permission set to allowed
2903:             * @param key the name of the property
2904:             * @param value the value of the property
2905:             *
2906:             * @exception SecurityException if the caller's token does not have
2907:             *            internal AMS permission
2908:             */
2909:            public void setTempProperty(SecurityToken token, String key,
2910:                    String value) {
2911:                throw new RuntimeException("Not Implemented");
2912:            }
2913:
2914:            /**
2915:             * Get the name of a MIDlet.
2916:             *
2917:             * @param classname classname of a MIDlet in the suite
2918:             *
2919:             * @return name of a MIDlet to show the user
2920:             */
2921:            public String getMIDletName(String classname) {
2922:                throw new RuntimeException("Not Implemented");
2923:            }
2924:
2925:            /**
2926:             * Checks to see the suite has the ALLOW level for specific permission.
2927:             * This is used for by internal APIs that only provide access to
2928:             * trusted system applications.
2929:             * <p>
2930:             * Only trust this method if the object has been obtained from the
2931:             * MIDletStateHandler of the suite.
2932:             *
2933:             * @param permission permission ID from
2934:             *      {@link com.sun.midp.security.Permissions}
2935:             *
2936:             * @exception SecurityException if the suite is not
2937:             *            allowed to perform the specified action
2938:             */
2939:            public void checkIfPermissionAllowed(int permission) {
2940:                throw new RuntimeException("Not Implemented");
2941:            }
2942:
2943:            /**
2944:             * Gets the status of the specified permission.
2945:             * If no API on the device defines the specific permission
2946:             * requested then it must be reported as denied.
2947:             * If the status of the permission is not known because it might
2948:             * require a user interaction then it should be reported as unknown.
2949:             *
2950:             * @param permission to check if denied, allowed, or unknown
2951:             * @return 0 if the permission is denied; 1 if the permission is
2952:             *    allowed; -1 if the status is unknown
2953:             */
2954:            public int checkPermission(String permission) {
2955:                throw new RuntimeException("Not Implemented");
2956:            }
2957:
2958:            /**
2959:             * Saves any the settings (security or others) that the user may have
2960:             * changed. Normally called by the scheduler after
2961:             * the last running MIDlet in the suite is destroyed.
2962:             * However it could be call during a suspend of the VM so
2963:             * that persistent settings of the suite can be preserved.
2964:             */
2965:            public void saveSettings() {
2966:                throw new RuntimeException("Not Implemented");
2967:            }
2968:
2969:            /**
2970:             * Asks the user want to interrupt the current MIDlet with
2971:             * a new MIDlet that has received network data.
2972:             *
2973:             * @param connection connection to place in the permission question or
2974:             *        null for alarm
2975:             *
2976:             * @return true if the use wants interrupt the current MIDlet,
2977:             * else false
2978:             */
2979:            public boolean permissionToInterrupt(String connection) {
2980:                throw new RuntimeException("Not Implemented");
2981:            }
2982:
2983:            /**
2984:             * Determine if the a MIDlet from this suite can be run. Note that
2985:             * disable suites can still have their settings changed and their
2986:             * install info displayed.
2987:             *
2988:             * @return true if suite is enabled, false otherwise
2989:             */
2990:            public boolean isEnabled() {
2991:                throw new RuntimeException("Not Implemented");
2992:            }
2993:
2994:            /**
2995:             * Close the opened MIDletSuite
2996:             */
2997:            public void close() {
2998:            }
2999:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.