FileDocCategorySizeDatePackage
InvocationImpl.javaAPI DocphoneME MR2 API (J2ME)32117Wed May 02 18:00:44 BST 2007com.sun.midp.content

InvocationImpl

public final class InvocationImpl extends Object
Implementation of Invocation class.

This class MUST NOT have any public methods that are not also public in Invocation (the superclass). The sensistive methods of the class MUST be package private.

Fields Summary
public javax.microedition.content.Invocation
invocation
The Invocation delegating to this instance. This field is public to Invocation can set it. This allows the implementation to pass a InvocationImpl to back to the Invocation class and it can wrap it in an Invocation before passing it to the application.
String
url
The URL of the content; may be null. URLs of up to and including 256 characters in length MUST be supported. A URL with a length of zero is treated as null and is ignored..
String
type
The content type; may be null.
String
ID
The content handler ID; may be null
String
action
The action to perform on the content; may be null
String[]
arguments
The array of arguments; may be null
int
argsLen
The length (returned by get0) of the argument array.
byte[]
data
The data array; may be null.
int
dataLen
The length (returned by get0) needed for the data array.
boolean
responseRequired
Set to true if the invoker must be notified of completion.
String
username
The username in case it is needed for authentication.
String
password
The password in case it is needed for authentication.
int
tid
Transaction Identifier.
int
suiteId
The MIDlet suite that should handle this Invocation.
String
classname
The classname of the MIDlet to deliver to.
int
status
The status of the request; one of {@link Invocation#ACTIVE}, {@link Invocation#WAITING}, {@link Invocation#ERROR}, {@link Invocation#OK}, or {@link Invocation#CANCELLED}.
String
invokingAuthority
The authority that authenticated this Invocation.
String
invokingID
The ID that authenticated this Invocation.
int
invokingSuiteId
The MIDlet suite of the invoking application.
String
invokingClassname
The classname in the invoking MIDlet suite for the response.
String
invokingAppName
The application name of the invoking MIDlet suite.
InvocationImpl
previous
The previous invocation, if any.
int
previousTid
The tid of the previous Invocation, if any.
private static final byte[]
ZERO_BYTES
A zero length array of strings to re-use when needed.
static final int
DISPOSE
The DISPOSE status is used with {@link #setStatus setStatus} to discard the native Invocation. It must not overlap with Status values defined in the Invocation class and must match STATUS_DISPOSE defined in invocStore.c.
Constructors Summary
InvocationImpl()
Create a fresh InvocationImpl.


             
     
        status = Invocation.INIT;
        responseRequired = true;
        arguments = ContentHandlerImpl.ZERO_STRINGS;
        data = ZERO_BYTES;
    
public InvocationImpl(javax.microedition.content.Invocation invocation)
Create a fresh InvocationImpl that is being delegated to byte an Invocation instance created by an application.

param
invocation the Invocation delegating to this implementation

        this();
        this.invocation = invocation;
    
Methods Summary
public java.lang.StringfindType()
Finds the type of the content in this Invocation. If the getType method return value is non-null, then the type is returned.

If the type is null and the URL is non-null, then the content type will be found by accessing the content through the URL. When found, the type is set as if the setType method was called; subsequent calls to {@link #getType getType} and {@link #findType findType} will return the type. If an exception is thrown, the getType method will return null.

The calling thread blocks while the type is being determined. If a network access is needed there may be an associated delay.

return
the non-null content type
exception
IOException if access to the content fails
exception
ContentHandlerException is thrown with a reason of {@link ContentHandlerException#TYPE_UNKNOWN} if the type is null and cannot be found from the content either because the URL is null or the type is not available from the content
exception
IllegalArgumentException if the content is accessed via the URL and the URL is invalid
exception
SecurityException is thrown if access to the content is required and is not permitted

        if (type != null) {
            return type;
        }
        if (url == null) {
            // No URL to examine, leave the type null
            throw new ContentHandlerException(
                                "URL is null",
                                ContentHandlerException.TYPE_UNKNOWN);
        }

        // Open a connection to the content.
        Connection conn = null;
        int rc = 0;
        try {
            while (true) {
                // Loop to enable redirects.
                conn = Connector.open(url);
                if (conn instanceof HttpConnection) {
                    HttpConnection httpc = (HttpConnection)conn;
                    httpc.setRequestMethod(httpc.HEAD);

                    // Get the response code
                    rc = httpc.getResponseCode();
                    if (rc == HttpConnection.HTTP_OK) {
                        type = httpc.getType();
                        if (type != null) {
                            // Check for and remove any parameters (rfc2616)
                            int ndx = type.indexOf(';");
                            if (ndx >= 0) {
                                type = type.substring(0, ndx);
                            }
                            type = type.trim();
                        }
                        if (type == null || type.length() == 0) {
                            type = null;
                            throw new ContentHandlerException(
                                "unable to determine type",
                                ContentHandlerException.TYPE_UNKNOWN);
                        }
                        break;
                    } else if (rc == HttpConnection.HTTP_TEMP_REDIRECT ||
                               rc == HttpConnection.HTTP_MOVED_TEMP ||
                               rc == HttpConnection.HTTP_MOVED_PERM) {
                        // Get the new location and close the connection
                        url = httpc.getHeaderField("location");

                        conn.close();
                        conn = null;
                        continue; // restart with the new url
                    } else {
                        throw new IOException("http status: " + rc);
                    }
                } else {
                    // Not HTTP, this isn't going to work
                    // TBD: Check suffixes
                    throw new ContentHandlerException(
                                "URL scheme not supported",
                                ContentHandlerException.TYPE_UNKNOWN);
                }
            }

        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (Exception ex) {
                }
            }
        }
        return type;
    
booleanfinish(int status)
Finish this Invocation and set the status for the response.

param
status the new status of the Invocation. This MUST be either OK or CANCELLED.
return
true if the MIDlet suite MUST voluntarily exit before the response can be returned to the invoking application
exception
IllegalArgumentException if the new status of the Invocation is not OK or CANCELLED

        if (status != Invocation.OK &&
            status != Invocation.CANCELLED &&
            status != Invocation.INITIATED) {
            throw new IllegalArgumentException();
        }

        /*
         * If a response is required by the invoking application,
         * the native code requeues it.
         * The application mutable parameters are saved to the
         * native invocation.
         */
        if (getResponseRequired()) {
            if (tid != 0) {
                InvocationStore.setParams(this);
            }
        }

        setStatus(status);

        if (getResponseRequired()) {
            // Launch the target application if necessary.
            try {
                AppProxy appl = AppProxy.getCurrent().
                    forApp(suiteId, classname);
                return appl.launch(invokingAppName);
            } catch (ClassNotFoundException cnfe) {
                AppProxy.getCurrent().logInfo(
                        "Unable to launch invoking application "
                        + invokingAppName + "; classname = "
                        + classname + " from suite = "
                        + suiteId);
            }
        }
        return false;
    
public java.lang.StringgetAction()
Gets the action to be performed on the content.

return
the content action or null if it has not been set
see
#setAction

        return action;
    
public java.lang.String[]getArgs()
Gets the argument list as an array of Strings. These values are passed to the content handler and are returned from the content handler. The array is not copied; modifications to array elements will be visible.

return
the arguments array, which MUST NOT be null
see
#setArgs

        return arguments;
    
public byte[]getData()
Gets the data for the Invocation. The data is passed to the content handler. The content handler may modify and return the data if it returns a response. The array is not copied; modifications to array elements will be visible.

return
the data array, which MUST NOT be null
see
#setData

        return data;
    
public java.lang.StringgetID()
Gets the content handler ID for this Invocation.

see
Registry#forID
return
the ID of the ContentHandler; may be null
see
#setID

        return ID;
    
public java.lang.StringgetInvokingAppName()
Get the user-friendly name of the application that invoked the content handler. This information is available only if the status is ACTIVE or HOLD. This information has been authenticated only if getInvokingAuthority is non-null.

return
the application's name if status is ACTIVE or HOLD; null otherwise
see
ContentHandler#getID

        if (status != Invocation.ACTIVE &&
            status != Invocation.HOLD) {
            return null;
        }
        return invokingAppName;
    
public java.lang.StringgetInvokingAuthority()
Gets the authority, if any, used to authenticate the application that invoked this request. This value MUST be null unless the device has been able to authenticate this application. If non-null, it is the string identifiying the authority. For example, if the application was a signed MIDlet, then this is the "subject" of the certificate used to sign the application.

The format of the authority for X.509 certificates is defined by the MIDP Printable Representation of X.509 Distinguished Names as defined in class javax.microedition.pki.Certificate.

return
the authority used to authenticate this application or null otherwise
exception
IllegalStateException if the current status is not ACTIVE or HOLD
see
ContentHandler#getAuthority

        if (status != Invocation.ACTIVE &&
            status != Invocation.HOLD) {
            return null;
        }
        return invokingAuthority;
    
public java.lang.StringgetInvokingID()
Gets the ID of the application that invoked the content handler. This information is available only if the status is ACTIVE or HOLD. This information has been authenticated only if getInvokingAuthority is non-null.

return
the application's ID if status is ACTIVE or HOLD; null otherwise
exception
IllegalStateException if the current status is not ACTIVE or HOLD
see
ContentHandler#getID

        if (status != Invocation.ACTIVE &&
            status != Invocation.HOLD) {
            return null;
        }
        return invokingID;
    
public com.sun.midp.content.InvocationImplgetPrevious()
Returns the previous Invocation linked to this Invocation by this application's previous call to {@link Registry#invoke(Invocation invoc, Invocation previous)}.

return
the previous Invocation, if any, set when this Invocation was invoked; null is returned if the Invocation was not invoked with a previous Invocation.

        return previous;
    
public booleangetResponseRequired()
Gets the responseRequired mode for this Invocation. If true, then the invoking application requires a response to the Invocation.

return
the current value of the responseRequired mode. If true, then a response must be returned to the invoking application.
see
#setResponseRequired

        return responseRequired;
    
public intgetStatus()
Returns the status of this Invocation, which can be INIT, WAITING, HOLD, ACTIVE, OK, CANCELLED, or ERROR. The application uses the status to determine how to process an Invocation returned from getInvocation.

see
javax.microedition.content.Registry#invoke
return
the current status of this Invocation

        return status;
    
public java.lang.StringgetType()
Gets the content type for the Invocation.

return
the content type or null if it has not been set
see
#setType
see
#findType

        return type;
    
public java.lang.StringgetURL()
Gets the URL for the invocation. The URL must be equal to the value set with {@link #setURL setURL}.

return
the URL or null if it has not been set
see
#setURL

        return url;
    
booleaninvoke(com.sun.midp.content.InvocationImpl previous, ContentHandlerImpl handler)
Checks this Invocation and uses the ID, type, URL, and action find a matching ContentHandler and queue this request to it. The actual launching of the application is done in the Registry. If the previous Invocation is null then a new transaction is created; otherwise, this Invocation will use the same transaction as the previous Invocation.

The status of this Invocation must be INIT. If there is a previous Invocation, that Invocation must have a status of ACTIVE.

Candidate content handlers are found as described in {@link Registry#findHandler Registry.findHandler}. If any handlers are found, one is arbitrarily selected for this Invocation.

The status of this Invocation is set to WAITING. If there is a non-null previous Invocation, its status is set to HOLD. A copy of the Invocation is made, the status is set to ACTIVE and then queued to the target content handler. If the invoked content handler is not running, it must be started as described in Invocation Processing.

The calling thread blocks while the content handler is being determined. If a network access is needed there may be an associated delay.

param
previous a previous Invocation for this Invocation; may be null
param
handler the ContentHandlerImpl that is the target
return
true if the application MUST first voluntarily exit before the content handler can be started; false otherwise
exception
IllegalArgumentException is thrown if:
  • the classname does not implement the lifecycle required by the Java runtime, or
  • the ID, type, and URL are all null, or
  • the argument array contains any null references
exception
IOException is thrown if the URL to be accessed is not available
exception
ContentHandlerException is thrown with a reason of:
  • TYPE_UNKNOWN if the type is not set and cannot be determined from the URL, or
  • NO_REGISTERED_HANDLER if there is no registered content handler for the type or ID
exception
IllegalStateException is thrown if the status of this Invocation is not INIT or if the status of the previous Invocation, if any, is not ACTIVE
exception
SecurityException if an invoke operation is not permitted

        /*
         * Check all of the arguments for validity.
         */
        for (int i = 0; i < arguments.length; i++) {
            if (arguments[i] == null) {
                throw new IllegalArgumentException("argument is null");
            }
        }

        if (previous != null) {
            this.previous = previous;
            this.previousTid = previous.tid;
        }

        // Fill information about the target content handler.
        setStatus(Invocation.INIT);
        setID(handler.ID);
        suiteId = handler.storageId;
        classname = handler.classname;

        // Queue this Invocation
        InvocationStore.put(this);

        // Launch the target application if necessary.
        boolean shouldExit = false;

        try {
            if (handler.registrationMethod ==
                                ContentHandlerImpl.REGISTERED_NATIVE) {
                shouldExit = RegistryStore.launch(handler);
                finish(Invocation.INITIATED);
            } else {
                try {
                    AppProxy appl = AppProxy.getCurrent().
                        forApp(suiteId, classname);
                    shouldExit = appl.launch(handler.getAppName());
                    // Set the status of this Invocation to WAITING
                    status = Invocation.WAITING;
                } catch (ClassNotFoundException cnfe) {
                    throw new ContentHandlerException(
                                "Invoked handler has been removed",
                                ContentHandlerException.NO_REGISTERED_HANDLER);
                }
            }
        } catch (ContentHandlerException che) {
            // remove this invocation from the queue before throwing
            setStatus(DISPOSE);
            throw che;
        }

        // Set the status of the previous invocation
        if (previous != null) {
            previous.setStatus(Invocation.HOLD);
        }
        return shouldExit;
    
static voidinvokeNext()
Execute the User Environment Policy to select the next application to run. Check for and select the next MIDlet suite to run based on the contents of the Invocation queue. From the most recently queued Invocation that is an Invocation in INIT. If none, find the most recently queued Invocation that is a response.

        InvocationImpl invoc = null;
        int tid;

        // Look for a recently queued Invocation to launch
        tid = 0;
        while ((invoc = InvocationStore.getByTid(tid, -1)) != null) {
            if (invoc.status == Invocation.INIT) {
                AppProxy.getCurrent().logInfo("invokeNext has request: " +
                                              invoc);
                if (invoc.suiteId != MIDletSuite.UNUSED_SUITE_ID &&
                        invoc.classname != null) {
                    try {
                        AppProxy appl = AppProxy.getCurrent().
                            forApp(invoc.suiteId, invoc.classname);
                        appl.launch("Application");
                        return;
                    } catch (ClassNotFoundException cnfe) {
                        // Ignore
                    }
                } else if (invoc.ID != null) {
                    // check if it is native handler
                    ContentHandlerImpl handler = RegistryStore.getHandler(null, 
                                        invoc.ID, RegistryStore.SEARCH_EXACT);
                    if (handler != null && 
                        handler.registrationMethod == 
                                        ContentHandlerImpl.REGISTERED_NATIVE) {
                        try {
                            RegistryStore.launch(handler);
                            invoc.finish(Invocation.INITIATED);
                            continue;
                        } catch (ContentHandlerException che) {
                            // Ignore
                        }
                    }
                }

                // can't process this invocation - remove it
                invoc.setStatus(DISPOSE);
            } else if (invoc.status == Invocation.ERROR) {
                AppProxy.getCurrent().logInfo("invokeNext has response: " +
                                              invoc);
                if (invoc.suiteId != MIDletSuite.UNUSED_SUITE_ID &&
                        invoc.classname != null) {
                    try {
                        AppProxy appl = AppProxy.getCurrent().
                            forApp(invoc.suiteId, invoc.classname);
                        appl.launch("Application");
                        return;
                    } catch (ClassNotFoundException cnfe) {
                        // Ignore
                    }
                }

                // can't process this invocation - remove it
                invoc.setStatus(DISPOSE);
            }
            tid = invoc.tid;
        }
    
public javax.microedition.io.Connectionopen(boolean timeouts)
Creates and opens a Connection to the content accessable by using the URL. This method is equivalent to {@link javax.microedition.io.Connector#open Connector.open} with the URL provided. The application should use this method to access the content of the URL so that any type or content information cached by the implementation can be fully utilized. The content is opened in read only mode.

param
timeouts a flag to indicate that the caller wants timeout exceptions
return
a Connection object
exception
ConnectionNotFoundException is thrown if:
  • there is no URL, or
  • the target URL cannot be found, or
  • the requested protocol type is not supported
exception
IOException if some other kind of I/O error occurs
exception
SecurityException may be thrown if access to the protocol handler is prohibited

        Connection conn = Connector.open(getURL(), Connector.READ, timeouts);
        return conn;
    
public voidsetAction(java.lang.String action)
Sets the action to be performed on the content.

param
action the action to be performed on the content; may be null
see
#getAction

        this.action = action;
    
public voidsetArgs(java.lang.String[] args)
Sets the argument list to a new array of Strings. The arguments are used by the application to communicate to the content handler and return results from the content handler. The values of the arguments are not checked when they are set. Instead, they are checked during {@link Registry#invoke Registry.invoke} to check that none of the values are null.

param
args the String array; may be null. A null argument is treated the same as a zero-length array
see
#getArgs

        this.arguments =
            (args == null) ? ContentHandlerImpl.ZERO_STRINGS : args;
    
public voidsetCredentials(java.lang.String username, char[] password)
Provide the credentials needed to access the content.

param
username the username; may be null
param
password the password for the username; may be null

        this.username = username;
        this.password = (password == null) ? null : new String(password);

    
public voidsetData(byte[] data)
Sets the data used for the Invocation. The data is used by the application to communicate to the content handler and return data from the content handler.

param
data the byte data array; may be null. A null is treated the same as a zero-length array
see
#getData

        this.data = (data == null) ? ZERO_BYTES : data;
    
public voidsetID(java.lang.String ID)
Sets the ID of the content handler for this Invocation.

param
ID of the content handler; may be null
see
#getID

        this.ID = ID;
    
public voidsetResponseRequired(boolean responseRequired)
Sets the responseRequired mode for this Invocation. If true, then the invoking application requires a response to the Invocation. The value in the request can be changed only if the status is INIT.

param
responseRequired true to require a response, false otherwise
exception
IllegalStateException is thrown if the status is not INIT
see
#getResponseRequired

        if (getStatus() != Invocation.INIT) {
            throw new IllegalStateException();
        }
        this.responseRequired = responseRequired;
    
voidsetStatus(int status)
Set the status of this InvocationImpl. If the invocation is still active in the native code set the status in native also.

param
status the new status

        this.status = status;
        if (tid != 0) {
            InvocationStore.setStatus(this);
        }
    
public voidsetType(java.lang.String type)
Sets the type for the Invocation.

param
type the type to be set for the content; may be null
see
#getType

        this.type = type;
    
public voidsetURL(java.lang.String url)
Sets the URL for the invocation.

param
url the URL to be set; may be null
see
#getURL

        this.url = url;
    
public java.lang.StringtoString()
Return a printable form of InvocationImpl. Disabled if not logging

return
a String containing a printable form

        if (AppProxy.LOG_INFO) {
            StringBuffer sb = new StringBuffer(200);
            sb.append("tid: ");         sb.append(tid);
            sb.append(" status: ");     sb.append(status);
            //        sb.append("  suiteId: ");   sb.append(suiteId);
            sb.append(", type: ");      sb.append(getType());
            sb.append(", url: ");       sb.append(getURL());
            sb.append(", respReq: ");   sb.append(getResponseRequired());
            //        sb.append(", args: ");      sb.append(getArgs());
            //        sb.append(", prevTid: ");   sb.append(previousTid);
            //        sb.append(", previous: ");
            //        sb.append((previous == null) ? "null" : "non-null");
            //        sb.append("_suiteId: ");    sb.append(invokingSuiteId);
            sb.append("\n   invokee: "); sb.append(classname);
            sb.append(", invoker: "); sb.append(invokingClassname);
            //        sb.append(", _authority: "); sb.append(invokingAuthority);
            //        sb.append(", _ID: ");       sb.append(invokingID);
            return sb.toString();
        } else {
            return super.toString();
        }