FileDocCategorySizeDatePackage
PushRegistryImpl.javaAPI DocJ2ME MIDP 2.030638Thu Nov 07 12:02:22 GMT 2002com.sun.midp.io.j2me.push

PushRegistryImpl

public class PushRegistryImpl extends Object implements Runnable, com.sun.midp.security.ImplicitlyTrustedClass
Inbound push connection watcher.

Fields Summary
private static com.sun.midp.security.SecurityToken
classSecurityToken
This class has a different security domain than the MIDlet suite
private static boolean
pushEnabled
Flag to control when push launching is permitted. This flag is set to false by the AMS when installing or removing MIDlets, when an interruption could compromise the integrity of the operation.
Constructors Summary
Methods Summary
private static native intadd0(byte[] connection)
Native connection registry add connection function.

param
connection string to register
return
0 if successful, -1 if failed

private static native longaddAlarm0(byte[] midlet, long time)
Native connection registry add alarm function.

param
midlet string to register
param
time
return
0 if unregistered, otherwise the time of the previous registered alarm

private static native intcheckInByName0(byte[] connection)
Native connection registry check in connection function.

param
connection string to register
return
0 if successful, -1 if failed

public static booleancheckInConnectionInternal(com.sun.midp.security.SecurityToken token, java.lang.String connection)
Check in a push connection into AMS so the owning MIDlet can get launched next time data is pushed. This method is used when a MIDlet will not be able to get the connection and close (check in) the connection for some reason. (normally because the user denied a permission)

For datagram connections this function will discard the cached message.

For server socket connections this function will close the accepted connection.

param
token security token of the calling class
param
connection generic connection protocol, host and port number (optional parameters may be included separated with semi-colons (;))
exception
IllegalArgumentException if the connection string is not valid
exception
SecurityException if the MIDlet does not have permission to clear a connection
return
true if the check in was successful, false the connection was not registered.
see
#unregisterConnection

	int ret;

	token.checkIfPermissionAllowed(Permissions.MIDP);
	/* Verify that the connection requested is valid. */
	if (connection == null || connection.length() == 0) {
	    throw new IllegalArgumentException("Connection missing");
	}
	
	byte[] asciiRegistration = Util.toCString(connection);

	return checkInByName0(asciiRegistration) != -1;
    
static voidcheckRegistration(java.lang.String connection, java.lang.String midlet, java.lang.String filter)
Check the registration arguments.

param
connection generic connection protocol, host and port number (optional parameters may be included separated with semi-colons (;))
param
midlet class name of the MIDlet to be launched, when new external data is available
param
filter a connection URL string indicating which senders are allowed to cause the MIDlet to be launched
exception
IllegalArgumentException if the connection string is not valid
exception
ClassNotFoundException if the MIDlet class name can not be found in the current MIDlet suite


	/* Verify the MIDlet is in the current classpath. */
	if (midlet == null || midlet.length() == 0) {
	    throw new ClassNotFoundException("MIDlet missing");
	}

	/* Verify that the connection requested is valid. */
	if (connection == null || connection.length() == 0) {
	    throw new IllegalArgumentException("Connection missing");
	}

	/* Verify that the filter requested is valid. */
	if (filter == null || filter.length() == 0) {
	    throw new IllegalArgumentException("Filter missing");
	}

	int len = filter.length();
	for (int i = 0; i < len; i++) {
	    char c = filter.charAt(i);
	    if (!(c == '?" || c == '*" || c == '." ||
		  ('0" <= c && c <= '9"))) {
		throw new IllegalArgumentException("Filter invalid");
	    }
	}
    
private static native intdel0(byte[] connection, byte[] storage)
Native connection registry del connection function.

param
connection string to register
param
storage current suite storage name
return
0 if successful, -1 if failed

private static native voiddelAllForSuite0(byte[] storageName)
Native connection registry delete a suite's connections function.

param
storageName native ASCII representation of a suite's storage name

public static voidenablePushLaunch(com.sun.midp.security.SecurityToken token, boolean enable)
Sets the flag which enables push launches to take place.

param
token security token of the calling class
param
enable set to true to enable launching of MIDlets based on alarms and connection notification events, otherwise set to false to disable launches

	token.checkIfPermissionAllowed(Permissions.MIDP);

	pushEnabled = enable;
    
private static native intgetEntry0(byte[] connection, byte[] regentry, int entrysz)
Native connection registry lookup registry entry from a specific connection.

param
connection registered connection string
param
regentry registered entry
param
entrysz maximum string that will be accepted
return
0 if successful, -1 if failed

public static java.lang.StringgetFilter(java.lang.String connection)
Retrieve the registered filter for a requested connection.

param
connection generic connection protocol, host and port number (optional parameters may be included separated with semi-colons (;))
return
a filter string indicating which senders are allowed to cause the MIDlet to be launched or null if the connection was not registered
see
#registerConnection


	/* Verify that the connection requested is valid. */
	if (connection == null || connection.length() == 0) {
	    return null;
	}

	String filter = null;
        byte[] asciiConn = Util.toCString(connection);
	byte[] registryEntry = new byte[512];

	if (getEntry0(asciiConn, registryEntry, 512) == 0) {
	    String name = Util.toJavaString(registryEntry);
	    try {
		int comma1 = name.indexOf(',", 0);
		int comma2 = name.indexOf(',", comma1 + 1);
		int comma3 = name.indexOf(',", comma2 + 1);
		
		filter = name.substring(comma2+1, comma3).trim();
	    } catch (Exception e) {
		e.printStackTrace();
	    }
	}
	return 	filter;
    
public static java.lang.StringgetMIDlet(java.lang.String connection)
Retrieve the registered MIDlet for a requested connection.

param
connection generic connection protocol, host and port number (optional parameters may be included separated with semi-colons (;))
return
class name of the MIDlet to be launched, when new external data is available, or null if the connection was not registered
see
#registerConnection


	/* Verify that the connection requested is valid. */
	if (connection == null || connection.length() == 0) {
	    return null;
	}

	String midlet = null;
        byte[] asciiConn = Util.toCString(connection);
	byte[] registryEntry = new byte[512];

	if (getEntry0(asciiConn, registryEntry, 512) == 0) {
	    String name = Util.toJavaString(registryEntry);
	    try {
		int comma1 = name.indexOf(',", 0);
		int comma2 = name.indexOf(',", comma1 + 1);
		
		midlet = name.substring(comma1+1, comma2).trim();
	    } catch (Exception e) {
		e.printStackTrace();
	    }
	}
	return 	midlet;
    
private static native intgetMIDlet0(long handle, byte[] regentry, int entrysz)
Native connection registry lookup for MIDlet name from file descriptor.

param
handle file descriptor of registered active connection
param
regentry registered entry
param
entrysz maximum string that will be accepted
return
0 if successful, -1 if failed

public 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) {
            classSecurityToken = token;
        }
    
protected voidlaunchEntry(java.lang.String name)
Parse the registration entry and launch the associtated MIDlet.

param
name registration string for connection and MIDlet to be launched

        String conn;
        String midlet;
        String filter;
        String storage;

	/* 	     
	 * Parse the comma separated values  - 	     
	 *  " connection, midlet,  filter, storagename"
	 *  "  midlet,  wakeup, storagename"
	 */
        int comma1 = name.indexOf(',", 0);
        int comma2 = name.indexOf(',", comma1 + 1);
        int comma3 = name.indexOf(',", comma2 + 1);
	    
        if (comma3 == -1) {
            /* Alarm was triggered */
            conn = null;
            midlet = name.substring(0, comma1).trim();
            storage = name.substring(comma2+1).trim();
        } else {
            conn = name.substring(0, comma1).trim();
            midlet = name.substring(comma1+1, comma2).trim();
            filter = name.substring(comma2+1, comma3).trim();
            storage = name.substring(comma3+1).trim();
        }

	try {
            boolean okToInterrupt = true;
	    
            /*
             * Check to see if the MIDlet is already scheduled.
             */
            Installer installer = Installer.getInstaller(classSecurityToken);
	    Scheduler scheduler = Scheduler.getScheduler();
	    MIDletSuite current = scheduler.getMIDletSuite();
	    String root = null;
	    if (current != null) {
		root = current.getStorageName();
	    }

	    if ((root != null) && root.equals(storage)) {
		/*
		 * The storage name matches the current running
		 * MIDlet do not start it.
                 */
		if (scheduler.isScheduled(midlet)) {
                    return;
                }

                if (!current.permissionToInterrupt(conn)) {
                    // user does not want the interruption
                    if (conn != null) {
                        checkInConnectionInternal(classSecurityToken, conn);
                    }

                    return;
                } 

                current.saveSettings();
            } else {
                MIDletSuite next = installer.getMIDletSuite(storage);
                if (next == null) {
                    return;
                }

		okToInterrupt = next.permissionToInterrupt(conn);
		next.saveSettings();

                if (!okToInterrupt) {
                    // user does not want the interruption
                    if (conn != null) {
                        checkInConnectionInternal(classSecurityToken, conn);
                    }

                    return;
                }
            }

	    /*
	     * Inform the Installer about the MIDlet to run next.
	     * Need to restart the VM to load the next suite.
	     */
	    installer.execute(storage, midlet);
	    
	    /*
	     * Shutdown all running applications.
	     * NYI, ask the user before doing a forced take down.
	     */
            Scheduler.getScheduler().shutdown();
	} catch (Exception e) {
	    // Could not launch requested push entry
            if (conn != null) {
                checkInConnectionInternal(classSecurityToken, conn);
            }

	    e.printStackTrace();
	}
    
private static native intlist0(byte[] midlet, boolean available, byte[] connectionlist, int listsz)
Native connection registry list connection function.

param
midlet string to register
param
available if true, only return the list of connections with input available
param
connectionlist comma separated string of connections
param
listsz maximum string that will be accepted in connectionlist
return
0 if successful, -1 if failed

public static java.lang.StringlistConnections(java.lang.String storageName, boolean available)
Return a list of registered connections for given MIDlet suite.

param
storageName identifies the specific MIDlet suite to be launched
param
available if true, only return the list of connections with input available
return
array of connection strings, where each connection is represented by the generic connection protocol, host and port number identification


        return listConnections(null, storageName, available);
    
public static java.lang.StringlistConnections(com.sun.midp.security.SecurityToken token, java.lang.String storageName, boolean available)
Return a list of registered connections for given MIDlet suite. Root permissions are required.

param
token security token of the calling class, or null to check the suite
param
storageName identifies the specific MIDlet suite to be launched
param
available if true, only return the list of connections with input available
return
array of connection strings, where each connection is represented by the generic connection protocol, host and port number identification

        byte[] nativeStorageName;
	String connections = null;
	byte[] connlist;

        if (token == null) {
            MIDletSuite current = Scheduler.getScheduler().getMIDletSuite();

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

        nativeStorageName = Util.toCString(storageName);
	connlist = new byte[512];

        if (list0(nativeStorageName, available, connlist, 512) == 0) {
            connections = Util.toJavaString(connlist);
        }

	return connections;
    
public static java.lang.StringlistConnections(boolean available)
Return a list of registered connections for the current MIDlet suite.

param
available if true, only return the list of connections with input available
return
array of connection strings, where each connection is represented by the generic connection protocol, host and port number identification

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

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

        return listConnections(classSecurityToken, current.getStorageName(),
                               available);
    
private native longpoll0(long time)
Native function to test registered inbound connections for new connection notification.

param
time current time to use for alarm checks
return
handle for the connection with inbound connection pending.

public static longregisterAlarm(java.lang.String midlet, long time)
Register a time to launch the specified application. The PushRegistry supports one outstanding wake up time per MIDlet in the current suite. An application is expected to use a TimerTask for notification of time based events while the application is running.

If a wakeup time is already registered, the previous value will be returned, otherwise a zero is returned the first time the alarm is registered.

param
midlet class name of the MIDlet within the current running MIDlet suite to be launched, when the alarm time has been reached
param
time time at which the MIDlet is to be executed in the format returned by Date.getTime()
return
the time at which the most recent execution of this MIDlet was scheduled to occur, in the format returned by Date.getTime()
exception
ConnectionNotFoundException if the runtime system does not support alarm based application launch
exception
ClassNotFoundException if the MIDlet class name can not be found in the current MIDlet suite
see
Date#getTime()
see
Timer
see
TimerTask


        Scheduler scheduler = Scheduler.getScheduler();
        MIDletSuite midletSuite = scheduler.getMIDletSuite();

        /* There is no suite running when installing from the command line. */
        if (midletSuite != null) {
            try {
                midletSuite.checkForPermission(Permissions.PUSH, null);
            } catch (InterruptedException ie) {
                throw new RuntimeException(
                    "Interrupted while trying to ask the user permission");
            }
        }

	/* Verify the MIDlet is in the current classpath. */
	if (midlet == null || midlet.length() == 0) {
	    throw new ClassNotFoundException("MIDlet missing");
	}

	/* Check if an appropriate MIDlet-<n> record exists. */
	if (!midletSuite.isRegistered(midlet)) {
	    throw new ClassNotFoundException("No MIDLet-<n> registration");
	}

	Class c = Class.forName(midlet);
	Class m = Class.forName("javax.microedition.midlet.MIDlet");

	if (!m.isAssignableFrom(c)) {
	    throw new ClassNotFoundException("Not a MIDlet");
	}

	/* 
	 * Add the alarm for the specified MIDlet int the current
	 * MIDlet suite.
	 */
	MIDletSuite current = Scheduler.getScheduler().getMIDletSuite();
	if (current != null) {
	    String root = current.getStorageName();

	    byte[] asciiName = Util.toCString(midlet + "," 
					      + time + "," 
					      + root); 
	    return addAlarm0(asciiName, time);
	}

	return 0;
    
public static voidregisterConnection(java.lang.String connection, java.lang.String midlet, java.lang.String filter)
Register a dynamic connection with the application management software. Once registered, the dynamic connection acts just like a connection preallocated from the descriptor file. The internal implementation includes the storage name that uniquely identifies the MIDlet.

param
connection generic connection protocol, host and port number (optional parameters may be included separated with semi-colons (;))
param
midlet class name of the MIDlet to be launched, when new external data is available
param
filter a connection URL string indicating which senders are allowed to cause the MIDlet to be launched
exception
IllegalArgumentException if the connection string is not valid
exception
ConnectionNotFoundException if the runtime system does not support push delivery for the requested connection protocol
exception
IOException if the connection is already registered or if there are insufficient resources to handle the registration request
exception
ClassNotFoundException if the MIDlet class name can not be found in the current MIDlet suite
exception
SecurityException if the MIDlet does not have permission to register a connection
see
#unregisterConnection


        Scheduler scheduler = Scheduler.getScheduler();
        MIDletSuite midletSuite = scheduler.getMIDletSuite();

        /* This method should only be called by scheduled MIDlets. */
        if (midletSuite == null) {
            throw new IllegalStateException("Not in a MIDlet context");
        }

	/* Verify the MIDlet is in the current classpath. */
	if (midlet == null || midlet.length() == 0) {
	    throw new ClassNotFoundException("MIDlet missing");
	}

	Class cl = Class.forName(midlet);
	Class m = Class.forName("javax.microedition.midlet.MIDlet");

	if (!m.isAssignableFrom(cl)) {
	    throw new ClassNotFoundException("Not a MIDlet");
	}

	/* Perform the rest of the checks in the internal registry. */
	registerConnectionInternal(classSecurityToken, midletSuite,
            connection, midlet, filter, false);
    
public static voidregisterConnectionInternal(com.sun.midp.security.SecurityToken token, com.sun.midp.midlet.MIDletSuite midletSuite, java.lang.String connection, java.lang.String midlet, java.lang.String filter, boolean bypassChecks)
Register a dynamic connection with the application management software. Once registered, the dynamic connection acts just like a connection preallocated from the descriptor file. The internal implementation includes the storage name that uniquely identifies the MIDlet. This method bypasses the class loader specific checks needed by the Installer.

param
token security token of the calling class
param
midletSuite MIDlet suite for the suite registering, the suite only has to implement isRegistered, checkForPermission, and getStorageName.
param
connection generic connection protocol, host and port number (optional parameters may be included separated with semi-colons (;))
param
midlet class name of the MIDlet to be launched, when new external data is available
param
filter a connection URL string indicating which senders are allowed to cause the MIDlet to be launched
param
bypassChecks if true, bypass the permission checks, used by the installer when redo old connections during an aborted update
exception
IllegalArgumentException if the connection string is not valid
exception
ConnectionNotFoundException if the runtime system does not support push delivery for the requested connection protocol
exception
IOException if the connection is already registered or if there are insufficient resources to handle the registration request
exception
ClassNotFoundException if the MIDlet class name can not be found in the current MIDlet suite
exception
SecurityException if the MIDlet does not have permission to register a connection
see
#unregisterConnection


        HttpUrl url;
        String storageName;

	token.checkIfPermissionAllowed(Permissions.MIDP);

        if (!bypassChecks) {
            try {
                midletSuite.checkForPermission(Permissions.PUSH, null);
                /* Check the registration arguments. */
                checkRegistration(connection, midlet, filter);
                    
                /* Check if an appropriate MIDlet-<n> record exists. */
                if (!midletSuite.isRegistered(midlet)) {
                    throw new
                        ClassNotFoundException("No MIDLet-<n> registration");
                }

                /*
                 * Only socket and datagram connections are supported by
                 * the MIDP 2.0 reference implementation. 
                 */
                url = new HttpUrl(connection);

                // Server connections do not have a host
                if (url.host != null) {
                    throw new ConnectionNotFoundException(
                        "Connection not supported");
                }
            
                /*
                 * Attempt to open the connection to perform security check
                 * int the context of the current MIDlet suite.
                 */

                if (connection.startsWith("socket://")) {
                    if (url.port == -1) {
                        new IllegalArgumentException("Port missing");
                    }

                    midletSuite.checkForPermission(Permissions.TCP_SERVER,
                                                   connection);
                } else if (connection.startsWith("datagram://")) {
                    /*
                     * Check the suite permission for the connection 
                     * and close the connection immediately.
                     */
                    midletSuite.checkForPermission(Permissions.UDP_SERVER,
                                                   connection);
                } else {
                    throw new ConnectionNotFoundException(
                        "Connection not supported");
                }
            } catch (InterruptedException ie) {
                throw new InterruptedIOException(
                    "Interrupted while trying to ask the user permission");
            }
        }

	storageName = midletSuite.getStorageName();

        byte[] asciiRegistration = Util.toCString(connection 
						      + "," + midlet 
						      + "," + filter
						      + "," + storageName);

        if (add0(asciiRegistration) == -1) {
            throw new IOException("Connection already registered");
        }
    
public voidrun()
Run the polling loop to check for inbound connections.


                      
       
	long fd = -1;
	int ret = 0;
	while (true) {
	    try {
		if (pushEnabled
		    && (fd = poll0(System.currentTimeMillis())) != -1) {
		    if (fd != -1) {
			byte[] registryEntry = new byte[512];
			if ((ret = getMIDlet0(fd, registryEntry, 512)) == 0) {
			    String name = Util.toJavaString(registryEntry);
			    launchEntry(name);
			} else {
			    // NYI - can't find entry after successful poll
			}
		    }
		}

		Thread.sleep(1000);
	    } catch (Exception e) {
		e.printStackTrace();
	    }
	}
    
public static booleanunregisterConnection(java.lang.String connection)
Remove a dynamic connection registration.

param
connection generic connection protocol, host and port number
exception
SecurityException if the connection was not registered by the current MIDlet suite
return
true if the unregistration was successful, false the connection was not registered.
see
#registerConnection

	
	/* Verify the connection string before using it. */
	if (connection == null || connection.length() == 0) {
	    return false;
	}
	Scheduler scheduler = Scheduler.getScheduler();
	MIDletSuite current = scheduler.getMIDletSuite();
	String root = current.getStorageName();

        byte[] asciiRegistration = Util.toCString(connection);
        byte[] asciiStorage = Util.toCString(root);
	int ret =  del0(asciiRegistration, asciiStorage);
	if (ret == -2) {
	    throw new SecurityException("wrong suite");
	}
	return ret != -1;
    
public static voidunregisterConnections(com.sun.midp.security.SecurityToken token, java.lang.String storageName)
Unregister all the connections for a MIDlet suite.

param
token security token of the calling class
param
storageName identifies the specific MIDlet suite

	token.checkIfPermissionAllowed(Permissions.MIDP);

	delAllForSuite0(Util.toCString(storageName));