FileDocCategorySizeDatePackage
MIDletSuiteImpl.javaAPI DocJ2ME MIDP 2.028905Thu Nov 07 12:02:24 GMT 2002com.sun.midp.midletsuite

MIDletSuiteImpl

public class MIDletSuiteImpl extends Object implements com.sun.midp.midlet.MIDletSuite
Implements a the required MIDletSuite functionality needed by the Scheduler.

Fields Summary
static final String
PUSH_INTERRUPT_DIALOG_TITLE
Interrupt dialog title for push.
protected static final String
PUSH_INTERRUPT_QUESTION
Interrupt question for push.
protected static final String
ALARM_INTERRUPT_QUESTION
Interrupt question for alarms.
private static com.sun.midp.security.SecurityToken
classSecurityToken
This class has a different security domain than the application.
private JadProperties
bufferedJadProps
Buffered properties from the application descriptor.
private ManifestProperties
bufferedJarProps
Buffered properties from the JAR manifest.
private com.sun.midp.security.SecurityToken
securityToken
Security token for this suite.
private byte[]
permissions
Permissions for this suite.
private int
pushInterruptSetting
Can this MIDlet suite interrupt other suites.
private String
storageRoot
The storage path of this suite.
private String
storageName
The storage name of this suite.
private String
ca
The CA that authorized this suite.
private boolean
trusted
Indicates if this suite is trusted.
private String
initialMIDletClassName
Initial midlet class name.
private int
numberOfMidlets
Number of midlets in this suite. less than 0 mean they need to counted.
Constructors Summary
protected MIDletSuiteImpl(com.sun.midp.security.SecurityToken callerSecurityToken, byte[] suitePermissions, int pushSetting, boolean trustedFlag, String theStorageName)
Constructor for development subclass.

param
callerSecurityToken security token for the calling class
param
suitePermissions security token of the suite
param
pushSetting can this MIDlet suite interrupt other suites
param
trustedFlag true if the suite is to considered trusted (not to be confused with a domain named "trusted", this only shown to the user and not used for permissions)
param
theStorageName name to separate this suite's storage from others


        callerSecurityToken.checkIfPermissionAllowed(Permissions.MIDP);

        permissions = suitePermissions;
        securityToken = new SecurityToken(classSecurityToken, permissions);
        pushInterruptSetting = pushSetting;
        trusted = trustedFlag;
        storageName = theStorageName;
    
MIDletSuiteImpl(com.sun.midp.security.SecurityToken callerSecurityToken, String theStorageRoot, String theStorageName, String theCA, String midletToRun)
Constructs MIDletSuiteImpl from an installed MIDlet Suite.

param
callerSecurityToken security token for the calling class
param
theStorageRoot root path of any files for this suite
param
theStorageName unique vendor and suite name identifying this suite
param
theCA name of CA that authorized this suite
param
midletToRun the name of the initial MIDlet in this suite to run, can be null

        callerSecurityToken.checkIfPermissionAllowed(Permissions.MIDP);

        storageRoot = theStorageRoot;

        storageName = theStorageName;

        ca = theCA;

        readSettings();

        securityToken = new SecurityToken(classSecurityToken, permissions);

        if (midletToRun != null) {
            initialMIDletClassName = getMIDletClassName(midletToRun);
        }
    
MIDletSuiteImpl(com.sun.midp.security.SecurityToken callerSecurityToken, String theStorageRoot, String theStorageName, String theCA, int midletToRun)
Constructs MIDletSuiteImpl from an installed MIDlet Suite.

param
callerSecurityToken security token for the calling class
param
theStorageRoot root path of any files for this suite
param
theStorageName unique vendor and suite name identifying this suite
param
theCA name of CA that authorized this suite
param
midletToRun the number of the initial MIDlet in this suite

        this(callerSecurityToken, theStorageRoot, theStorageName,
             theCA, null);

        String temp;

        temp = getProperty("MIDlet-" + midletToRun);
        if (temp == null) {
            return;
        }

        initialMIDletClassName = new MIDletInfo(temp).classname;
    
Methods Summary
public voidaddProperty(java.lang.String key, java.lang.String value)
Adds a property to the suite.

param
key the name of the property
param
value the value of the property
exception
SecurityException if the calling suite does not have internal API permission

        MIDletSuite current = Scheduler.getScheduler().getMIDletSuite();

        if (current != null) {
            current.checkIfPermissionAllowed(Permissions.MIDP);
        }

        if (bufferedJadProps != null) {
            bufferedJadProps.addProperty(key, value);
            return;
        }

        bufferedJarProps.addProperty(key, value);
    
public voidcheckForPermission(int permission, java.lang.String resource)
Checks for permission and throw an exception if not allowed. May block to ask the user a question.

param
permission ID of the permission to check for, the ID must be from {@link com.sun.midp.security.Permissions}
param
resource string to insert into the permission question, can be null
exception
SecurityException if the permission is not allowed by this token
exception
InterruptedException if another thread interrupts the calling thread while this method is waiting to preempt the display.

        checkForPermission(permission,
            getProperty(Installer.SUITE_NAME_PROP), resource);
    
protected voidcheckForPermission(int permission, java.lang.String name, java.lang.String resource)
Checks for permission and throw an exception if not allowed. May block to ask the user a question.

param
permission ID of the permission to check for, the ID must be from {@link com.sun.midp.security.Permissions}
param
name name of the suite
param
resource string to insert into the question, can be null
exception
SecurityException if the permission is not allowed by this token
exception
InterruptedException if another thread interrupts the calling thread while this method is waiting to preempt the display.

        String protocolName = null;

        try {
            int colon = resource.indexOf(':");

            if (colon != -1) {
                protocolName = resource.substring(0, colon);
            }
        } catch (Exception e) {
            // ignore
        }

        securityToken.checkForPermission(permission,
                                         Permissions.getTitle(permission),
                                         Permissions.getQuestion(permission),
                                         name, resource, protocolName);
    
public voidcheckIfPermissionAllowed(int permission)
Checks to see the suite has the ALLOW level for specific permission. This is used for by internal APIs that only provide access to trusted system applications.

param
permission permission ID from com.sun.midp.security.Permissions
exception
SecurityException if the suite is not ALLOWed the permission

        securityToken.checkIfPermissionAllowed(permission);
    
public intcheckPermission(java.lang.String permission)
Gets the status of the specified permission. If no API on the device defines the specific permission requested then it must be reported as denied. If the status of the permission is not known because it might require a user interaction then it should be reported as unknown.

param
permission to check if denied, allowed, or unknown
return
0 if the permission is denied; 1 if the permission is allowed; -1 if the status is unknown

        return securityToken.checkPermission(permission);
    
protected byte[][]copyPermissions(byte[][] permissions)
Makes a copy of a list of permissions.

param
permissions source copy
return
array of permissions from {@link Permissions}

        if (permissions == null) {
            return null;
        }

        byte[][] copy = new byte[2][];
        for (int i = 0; i < 2; i++) {
            copy[i] = new byte[permissions[i].length];
            System.arraycopy(permissions[i], 0, copy[i], 0,
                             permissions[i].length);
        }

        return copy;
    
protected intcountMIDlets()
Counts the number of MIDlets from its properties.

return
number of midlet in the suite

        int i;

        for (i = 1; getProperty("MIDlet-" + i) != null; i++);

        return i - 1;
    
protected java.lang.StringgetAlarmInterruptQuestion()
Gets the Alarm interrupt question the should be used when interrupting this suite.

The question will have %2 where this suite name should be and a %1 where the current suite name should be.

return
alarm interrupt question

        return ALARM_INTERRUPT_QUESTION;
    
public java.lang.StringgetCA()
Gets the name of CA that authorized this suite.

return
name of a CA or null if the suite was not signed

        return ca;
    
public java.lang.StringgetDownloadUrl()
Gets the URL that the suite was downloaded from.

return
URL of the JAD, or JAR for a JAR only suite, never null, even in development environments

        String url = getJadUrl();

        if (url != null) {
            return url;
        }

        return getJarUrl();
    
public java.lang.StringgetInitialMIDletClassname()
Gets the classname of the initial MIDlet to run.

return
classname of a MIDlet

        if (initialMIDletClassName != null) {
            return initialMIDletClassName;
        }

        if (getNumberOfMIDlets() == 1) {
            return new MIDletInfo(getProperty("MIDlet-1")).classname;
        }

        // Have the user select a MIDlet.
        return "com.sun.midp.midlet.Selector";
    
public java.lang.StringgetJadUrl()
Gets the JAD URL of the suite. This is only for the installer.

return
URL of the JAD can be null

        RandomAccessStream storage =
            new RandomAccessStream(classSecurityToken);
        DataInputStream storageStream;

        try {
            storage.connect(getStorageRoot() + Installer.JAD_URL_FILENAME,
                            Connector.READ);

            // convert the JAD URL to UTF8 and write it to storage
            storageStream = storage.openDataInputStream();
            return storageStream.readUTF();
        } catch (Exception e) {
            // ignore, not all suite have JAD URLs
            return null;
        } finally {
            try {
                storage.disconnect();
            } catch (IOException e) {
                // ignore
            }
        }

    
public java.lang.StringgetJarUrl()
Gets the JAR URL of the suite. This is only for the installer.

return
URL of the JAR, never null, even in development environments

        RandomAccessStream storage =
            new RandomAccessStream(classSecurityToken);
        DataInputStream storageStream;

        try {
            storage.connect(getStorageRoot() + Installer.JAR_URL_FILENAME,
                            Connector.READ);

            // convert the JAR URL to UTF8 and write it to storage
            storageStream = storage.openDataInputStream();
            return storageStream.readUTF();
        } catch (Exception e) {
            // old installations did not have JAR URL's
            return "unknown";
        } finally {
            try {
                storage.disconnect();
            } catch (IOException e) {
                // ignore
            }
        }
    
protected java.lang.StringgetMIDletClassName(java.lang.String midletName)
Retrieves the classname for a given MIDlet name.

param
midletName the name of the MIDlet to find
return
the classname of the MIDlet. null if the MIDlet cannot be found

        String midlet;
        MIDletInfo midletInfo;

        for (int i = 1; ; i++) {
            midlet = getProperty("MIDlet-" + i);
            if (midlet == null) {
		/*
		 * If the name was a class name use it. 
		 * (Temporary implemention - overloading the 
		 * name as MIDlet name or class name could be in
		 * conflict. Longer term solution would expand
		 * Installer.execute() semantics to allow a class
		 * name to run, rather than just the indirection
		 * via MIDlet info.)
		 */
		try {
		    Class.forName(midletName);
		    return midletName;
		} catch (Exception e) {}

                return null; // We went past the last MIDlet
            }

            midletInfo = new MIDletInfo(midlet);
            if (midletInfo.name.equals(midletName)) {
                return midletInfo.classname;
            }
        }
    
public intgetNumberOfMIDlets()
Provides the number of of MIDlets in this suite.

return
number of MIDlet in the suite

        if (numberOfMidlets <= 0) {
            numberOfMidlets = countMIDlets();
        }

        return numberOfMidlets;
    
public byte[][]getPermissions()
Gets list of permissions for this suite.

return
array of permissions from {@link Permissions}

        return copyPermissions(permissions);
    
private voidgetPropertiesFromStorage()
Gets properites from a symbolically named installed package. The properties are the attributes in the application descriptor and JAR Manifest.

        RandomAccessStream myStorage;
        int size;
        byte[] buffer;
        InputStream is;
        DataInputStream dis;
        String jadEncoding = null;

        myStorage = new RandomAccessStream(classSecurityToken);

        // Get the JAD encoding, if the server provided one
        try {
            myStorage.connect(storageRoot +
                              Installer.JAD_ENCODING_FILENAME,
                              Connector.READ);
            try {
                // convert the JAD encoding to UTF8 and write it to storage
                dis = myStorage.openDataInputStream();
                try {
                    jadEncoding = dis.readUTF();
                } finally {
                    dis.close();
                }
            } finally {
                myStorage.disconnect();
            }
        } catch (IOException e) {
            // servers can choose the default encoding by not providing one
        }

        // Load .jad file
        bufferedJadProps = new JadProperties();
        try {
            myStorage.connect(storageRoot + Installer.JAD_FILENAME,
                              Connector.READ);
            try {
                size = myStorage.getSizeOf();
                buffer = new byte[size];
                dis = myStorage.openDataInputStream();
                try {
                    dis.readFully(buffer);
                    is = new ByteArrayInputStream(buffer);

                    bufferedJadProps.load(is, jadEncoding);

                    buffer = null;
                    is = null;
                } finally {
                    dis.close();
                }
            } finally {
                myStorage.disconnect();
            }
        } catch (IOException e) {
            // Jar only install
        }

        try {
            // Get Manifest file so we can buffer it
            myStorage.connect(storageRoot + Installer.MANIFEST_FILENAME,
                              Connector.READ);
            try {
                size = myStorage.getSizeOf();
                buffer = new byte[size];
                dis = myStorage.openDataInputStream();
                try {
                    dis.readFully(buffer);
                    is = new ByteArrayInputStream(buffer);

                    bufferedJarProps = new ManifestProperties();
                    bufferedJarProps.load(is);

                    buffer = null;
                    is = null;
                } finally {
                    dis.close();
                }
            } finally {
                myStorage.disconnect();
            }
        } catch (IOException e) {
            // ignore
        }
    
public java.lang.StringgetProperty(java.lang.String key)
Gets a property of the suite. A property is an attribute from either the application descriptor or JAR Manifest.

param
key the name of the property
return
A string with the value of the property. null is returned if no value is available for the key.

        String prop;

        if (bufferedJadProps == null) {
            getPropertiesFromStorage();
            if (bufferedJadProps == null) {
                return null;
            }
        }

        // check the JAD first
        prop = bufferedJadProps.getProperty(key);
        if (prop != null) {
            return prop;
        }

        if (bufferedJarProps == null) {
            return null;
        }

        return bufferedJarProps.getProperty(key);
    
protected java.lang.StringgetPushInterruptQuestion()
Gets the Push interrupt question the should be used when interrupting this suite.

The question will have %2 where this suite name should be and a %1 where the current suite name should be.

return
push interrupt question

        return PUSH_INTERRUPT_QUESTION;
    
public intgetPushInterruptSetting()
Gets push setting for interrupting other MIDlets. Reuses the Permissions.

return
push setting for interrupting MIDlets the value will be permission level from {@link Permissions}

        return pushInterruptSetting;
    
public byte[]getResource(java.lang.String name)
Get a named resource out of the JAR of this MIDlet suite.

param
name name of the resource
return
raw bytes of the resource or null if not available

        if (name.charAt(0) == '/") {
            // the jar reader does not remove the leading '/'
            name = name.substring(1, name.length());
        }

        try {
            return JarReader.readJarEntry(classSecurityToken,
                                          getStorageRoot() +
                                          Installer.JAR_FILENAME,
                                          name);
        } catch (IOException e) {
            return null;
        }
    
public java.lang.StringgetStorageName()
Gets the unique name of vendor and suite.

return
storage name

        return storageName;
    
public java.lang.StringgetStorageRoot()
Gets the path root of any file this suite. Has any needed file separators appended.

return
storage path root

        return storageRoot;
    
public intgetStorageUsed()
Gets the amount of storage on the device that this suite is using. This includes the JAD, JAR, management data, and RMS.

return
number of bytes of storage the suite is using

        File file = new File(classSecurityToken);
        RandomAccessStream stream =
            new RandomAccessStream(classSecurityToken);
        Vector files;
        int storageUsed = 0;

        files = file.filenamesThatStartWith(getStorageRoot());
        for (int i = 0; i < files.size(); i++) {
            try {
                stream.connect((String)files.elementAt(i), Connector.READ);
                try {
                    storageUsed += stream.getSizeOf();
                } finally {
                    stream.disconnect();
                }
            } catch (IOException ioe) {
                // just move on to the next file
            }
        }

        return storageUsed;
    
protected java.lang.StringgetSuiteNameForInterrupt()
Gets the suite name for interruption purposes.

return
name for interrupt question

        return getProperty(Installer.SUITE_NAME_PROP);
    
static voidinitSecurityToken(com.sun.midp.security.SecurityToken token)
Initializes the security token for this class, so it can perform actions that a normal MIDlet Suite cannot.

param
token security token for this class


                                  
        
        if (classSecurityToken != null) {
            return;
        }

        classSecurityToken = token;
    
public booleanisRegistered(java.lang.String midletName)
Indicates if the named MIDlet is registered in the suite with MIDlet-<n> record in the manifest or application descriptor.

param
midletName class name of the MIDlet to be checked
return
true if the MIDlet is registered

        String midlet;
        MIDletInfo midletInfo;

        for (int i = 1; ; i++) {
            midlet = getProperty("MIDlet-" + i);
            if (midlet == null) {
                return false; // We went past the last MIDlet
            }

	    /* Check if the names match. */
            midletInfo = new MIDletInfo(midlet);
            if (midletInfo.classname.equals(midletName)) {
                return true;
            }
        }
    
public booleanisTrusted()
Indicates if this suite is trusted. (not to be confused with a domain named "trusted", this is used to determine if a trusted symbol should be displayed to the user and not used for permissions)

return
true if the suite is trusted false if not

        return trusted;
    
public booleanpermissionToInterrupt(java.lang.String connection)
Asks the user want to interrupt the current MIDlet with a new MIDlet that has received network data.

param
connection connection to place in the permission question or null for alarm
return
true if the use wants interrupt the current MIDlet, else false

        String name;
        MIDletSuite current;
        String question;
        String currentName;

        if (pushInterruptSetting == Permissions.USER_DENIED ||
                pushInterruptSetting == Permissions.NEVER) {
            return false;
        }

        // treat SESSION level the same as ONE_SHOT

        switch (pushInterruptSetting) {
        case Permissions.ALLOW:
        case Permissions.BLANKET_GRANTED:
            return true;
        }

        name = getSuiteNameForInterrupt();

        // The currently running suite controls what question to ask.
        current = Scheduler.getScheduler().getMIDletSuite();
        if (current instanceof MIDletSuiteImpl) {
            MIDletSuiteImpl temp = (MIDletSuiteImpl)current;
            if (connection == null) {
                question = temp.getAlarmInterruptQuestion();
            } else {
                question = temp.getPushInterruptQuestion();
            }

            currentName = temp.getSuiteNameForInterrupt();
        } else {
            // use the questions of this suite
            if (connection == null) {
                question = getAlarmInterruptQuestion();
            } else {
                question = getPushInterruptQuestion();
            }

            currentName = Resource.getString("The current application");
        }            

        try {
            switch (SecurityToken.askUserForPermission(classSecurityToken,
                    "Can %1 Interrupt?", question, name, currentName, null,
                    Permissions.BLANKET, pushInterruptSetting)) {
            case Permissions.BLANKET:
                pushInterruptSetting = Permissions.BLANKET_GRANTED;
                return true;

            case Permissions.SESSION:
            case Permissions.ONE_SHOT:
                // treat one shot as session
                pushInterruptSetting = Permissions.SESSION;
                return true;

            case Permissions.DENY:
                pushInterruptSetting = Permissions.USER_DENIED;
                return false;
            }
        } catch (InterruptedException ie) {
            return false;
        }

        // default, is cancel, ask again next time
        pushInterruptSetting = Permissions.DENY_SESSION;
        return false;
    
private voidreadSettings()
Reads the suite settings from storage.

        byte[] maximums = Permissions.getEmptySet();
        byte[] currentLevels = Permissions.getEmptySet();
        RandomAccessStream storage =
            new RandomAccessStream(classSecurityToken);
        DataInputStream storageStream;
        int version;
        int count;

        permissions = new byte[2][];
        permissions[Permissions.MAX_LEVELS] = maximums;
        permissions[Permissions.CUR_LEVELS] = currentLevels;

        try {
            storage.connect(getStorageRoot() + Installer.SETTINGS_FILENAME,
                            Connector.READ);
            try {
                storageStream = storage.openDataInputStream();

                version = storageStream.readByte();
                /*
                 * only version 1 are handled by the method
                 * 0 means that this is a beta version that are not handled
                 * by the method. Note that version number only has to
                 * increase if data has been removed, not if new data has been
                 * added to the end of the file.
                 */
                if (version != 1) {
                    System.out.println("Corrupt application settings file.");
                    return;
                }

                trusted = storageStream.readBoolean();

                pushInterruptSetting = storageStream.readByte();

                count = storageStream.readByte();
                storageStream.readFully(currentLevels, 0, count);

                count = storageStream.readByte();
                storageStream.readFully(maximums, 0, count);
            } finally {
                storage.disconnect();
            }
        } catch (IOException e) {
            // ignore, old settings files are shorter
        }
    
public voidsaveSettings()
Saves any the settings (security or others) that the user may have changed. Normally called by the scheduler after the last running MIDlet in the suite is destoryed. However it could be called during a suspend of the VM so that persisent settings of the suite can be perserved or by the graphical manager application settings MIDlet.

        try {
            Installer.saveSuiteSettings(classSecurityToken, storageRoot,
                (byte)pushInterruptSetting, permissions, trusted);
        } catch (IOException e) {
            // ignore
        }