Source Code Cross Referenced for JUMPInstaller.java in  » 6.0-JDK-Modules » j2me » com » sun » midp » jump » 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.jump.installer 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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