/* * * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package javax.microedition.content; import java.io.IOException; import com.sun.j2me.content.ContentHandlerImpl; import com.sun.j2me.content.ContentHandlerServerImpl; import com.sun.j2me.content.InvocationImpl; import com.sun.j2me.content.RegistryImpl; import com.sun.j2me.security.Token; import com.sun.j2me.security.TrustedClass; import com.sun.jsr211.security.SecurityInitializer; /** * The <tt>Registry</tt> provides method to invoke, * register, * unregister, and query information about content handlers. * An application registers, for each content handler, * zero or more content types, suffixes, and actions. * Access to the registry is via the {@link #getRegistry getRegistry} * method. The Registry class is thread safe. * Applications are responsible for the thread safety of * Invocation objects passed as arguments to Registry methods. * <p> * Multiple content handlers can be registered for each type, suffix, * and action. * The types, suffixes, and actions registered for a handler * can be used to select a handler. * The content handler ID is set during registration and is * used to uniquely identify the content handler * and to enforce access controls. * * <p> * A content handler is any application that is registered to * handle some content. It responds to requests and displays * or acts on the content. * Registration can occur dynamically or statically. * Static registration occurs during the installation of the * application package, while dynamic registration occurs via this API. * A content handler may be a Java or a non-Java application. * For example, MIDlet suites and Personal Basis Profile applications * using the Xlet application model can be content handlers. * Refer to the {@link ContentHandler ContentHandler} * class for information on registering Java platform content handlers.</P> * * <p> * When a content handler is processing an invocation, it may be * necessary to invoke another content handler before it is able * to satisfy the first request. * The invocation and chaining of content handlers is managed * to maintain the context and sequence across * application executions.</p> * * <P> * The term <em>application</em> is used more generally than the term * <em>content handler</em>. * The term application is used to refer to the * common handling for making requests, handling responses, * and querying the content handler registrations. * The term <em>content handler</em> is used for an application * that registers for types, suffixes, actions, etc. and processes * the requests queued to it.</p> * * * <H3>Content Types</H3> * <P> * A content handler can register a set of types that it can handle. * Content types are simple opaque strings that are NOT case sensitive. * Type strings are not case sensitive, types that differ * only by case are treated as a single type. * </P> * * <h3>Suffix Processing</h3> * <P> * A content handler can register a set of suffixes that identify * from the syntax of a URL the content it can handle. * Suffixes are NOT case sensitive. * </P> * * <H3>Content Handler Actions</H3> * <P>Each content handler may register a set of actions * it supports. * The set of actions is extensible but applications should * choose from the actions defined in the {@link ContentHandler} * class when they are appropriate. * The predefined actions are: * {@link ContentHandler#ACTION_OPEN open}, * {@link ContentHandler#ACTION_EDIT edit}, * {@link ContentHandler#ACTION_NEW new}, * {@link ContentHandler#ACTION_SEND send}, * {@link ContentHandler#ACTION_SAVE save}, * {@link ContentHandler#ACTION_EXECUTE execute}, * {@link ContentHandler#ACTION_SELECT select}, * {@link ContentHandler#ACTION_INSTALL install}, * {@link ContentHandler#ACTION_PRINT print}, and * {@link ContentHandler#ACTION_STOP stop}. * * * <H3>Content Handler IDs</H3> * <P>The content handler ID is a string chosen by the * application vendor to identify the content handler. The * ID registered by a content handler MUST be unique and MUST NOT * match the prefix of any other registered content handler. * IDs are case sensitive and are treated as opaque strings. * They are compared for equality or as prefixes of IDs * when used to locate an appropriate content handler. * </P> * * <P>Content handler IDs should follow the form of * fully qualified Java class names or any naming * syntax that provides a natural way to disambiguate between * vendors. For example, IDs may be URLs * including scheme, authority (server), and path information.</P> * <p> * For example, if registered in the order below, * the following content handler IDs would be valid * or invalid as indicated because there is an ambiguity due * to prefix comparisons. * <ol> * <li><code>com.sun.applications.calc</code> - valid</li> * <li><code>com.sun.applications.trig</code> - valid</li> * <li><code>com.sun.application</code> - invalid, * this is the prefix of the <code>calc</code> ID</li> * <li><code>com.sun.applications.calc.decimal</code> - * invalid, the <code>calc</code> ID is prefix of <code>decimal</code></li> * </ol> * * <H3>Java Application Class</H3> * <P>The content handler to be launched is identified by the * application class. The class MUST contain entry point(s) * and be packaged according to the Java runtime environment. * For MIDP, the application class MUST extend * <code>javax.microedition.midlet.MIDlet</code>. * The application class uniquely identifies a content handler * within the application package, which is usually a JAR file. * Each application class can only be registered to a single content * handler. Registering a content handler for a class will replace any * content handler previously registered to that class. * * <h3>Content Handler Authentication</h3> * Applications and content handlers using the API may, * for security purposes, need or want to authenticate * the invoked content handler or the invoking application. * The CHAPI implementation cooperates with the application management * software to authenticate the applications (if possible) and pass the * authentication information to the application. If the application * can be authenticated, then the * {@link ContentHandler#getAuthority ContentHandler.getAuthority} * method will return the authority used in the authentication. * <p> * While processing an invocation request the content handler can use the * {@link Invocation#getInvokingAuthority Invocation.getInvokingAuthority} * method to verify the authenticity of the invoking application.</p> * * <h3>Content Handler Access Control</h3> * The visibility and accessibility of a content handler * can be controlled by the content handler itself either through * dynamic or static registration. To restrict * access and visibility, the content handler MUST provide the IDs of * the content handlers that MUST be allowed access. * If any of the allowed IDs match * the beginning of the ID of the content handler requesting access, then the * application will be granted visibility and access to * the content handler. The comparison is performed as * if the <code>java.lang.string.startsWith</code> method was used. * The access controls are only visible to the content handler * itself using the method * {@link ContentHandlerServer#getAccessAllowed * ContentHandlerServer.getAccessAllowed}. * * By default, * access is allowed to all applications and content handlers. * Access restrictions are established when the content handler is * registered with the {@link #register register} method. * * <A NAME="dynamic"><h3>Dynamic Registration</h3></A> * <p> * Dynamic registration is performed by * initializing the classname, types, suffixes, * actions, action names, ID, and access restrictions, and passing * them to the {@link #register register} method. * The {@link #unregister unregister} method removes * a registered content handler. * <p> * The current registrations can be examined by using various methods to * get the {@link #getTypes types}, * {@link #getIDs IDs}, * {@link #getSuffixes suffixes}, * {@link #getActions actions}, * or to find a content handler * by content handler {@link #getServer classname}, or * to get all of the matching content handlers * by {@link #forID ID}, * by {@link #forType content type}, * by {@link #forSuffix suffix}, or * by {@link #forAction action}. * Only content handlers that are accessible and visible to the * application will be returned. * * <h3><A name="execution"></A>Invoking a Content Handler</h3> * <P> * To invoke a content handler, an application initializes an * Invocation instance with the information needed to identify the * content and/or the content handler. Typically this could include the * URL, type, action, and content handler ID. * The application may also supply arguments and data, and set * whether a response is required. * * The application may request information about the content * and the content handler that will process it before invocation. * * Calling the {@link Registry#invoke Registry.invoke} method * starts the request. * <P> * When invoked, the ID, type, URL, and action are used to identify a * target content handler. If multiple content handlers are registered * for the ID, type, suffixes or action, the implementation can decide * which to use to satisfy the request. If the application needs to * select which handler to use, the * {@link Registry#findHandler findHandler} method will * return the set of matching ContentHandlers. The application can * choose from the content handlers returned and use * {@link Invocation#setID Invocation.setID} * to select a specific handler. * <P> * In a runtime environment in which only a single application can * run at a time, the invoking application must exit before the * content handler can be started to handle the request. * Invocation requests are queued so that the invoking * application and the content handler can be run sequentially in * resource-constrained environments. * The return value of {@link Registry#invoke invoke} * is <code>true</code> to indicate that the application must exit. * This allows the invoking application to save the users context * and leave the user interface, if any, with some visual that the * user will see until the content handler is ready.</P> * * <P> * Invocation processing involves the invoking application, * the invoked * content handler, and the application management software (AMS). * The implementation of the API and the AMS MUST implement the * queuing of invocations to the appropriate content handler and * the necessary interactions with the lifecycle to start and * restart applications and content handlers. * <p> * The {@link Registry#invoke invoke} methods initiate the request. * The URL, type, action, and ID, as described above, are used to * dispatch the request to an appropriate content handler. * If the content handler is not running, it MUST be started to process * the request. If the content handler is already running, * then the new request MUST be queued to the content handler. * Only a single instance of each content handler application can be * active at a time. * The {@link ContentHandlerServer} class is used to dequeue and process * requests. */ public class Registry { /** * Inner class to request security token from SecurityInitializer. * SecurityInitializer should be able to check this inner class name. */ static private class SecurityTrusted implements TrustedClass { }; /** This class has a different security domain than the MIDlet suite */ private static Token classSecurityToken = SecurityInitializer.requestToken(new SecurityTrusted()); /** The mutex used to avoid corruption between threads. */ private static final Object mutex = new Object(); /** The reference to the RegistryImpl with the real implementation. */ private RegistryImpl impl; /** * Gets the Registry for the application or content handler * that will be calling registry methods. * The application is identified by the classname that implements * the lifecycle of the Java runtime environment. * The classname must be the name of a registered application class * or a registered content handler. * <p> * For a MIDP implementation, * application classes must be registered with the * <code>MIDlet-<n></code> attribute; content handlers are * registered with the <code>MicroEdition-Handler-<n></code> * attribute or the {@link #register register} method. * * @param classname the application class * @return a Registry instance providing access to content handler * registrations and invocations; MUST NOT be <code>null</code> * @exception IllegalArgumentException is thrown if the classname * is not a registered application or content handler * @exception NullPointerException if <code>classname</code> is * <code>null</code> */ public static Registry getRegistry(String classname) { // Find the RegistryImpl instance and get/create the Registry try { return findRegistryImpl(classname).getRegistry(); } catch (ContentHandlerException che) { throw new IllegalArgumentException(che.getMessage()); } } /** * Gets the RegistryImpl for the classname. * Create the Registry instance if it has not already been created. * * @param classname the classname * @return RegistryImpl * * @exception ContentHandlerException is thrown with a reason of * <code>NO_REGISTERED_HANDLER</code> if the classname * is not a registered application or content handler */ private static RegistryImpl findRegistryImpl(String classname) throws ContentHandlerException { synchronized (mutex) { RegistryImpl impl = RegistryImpl.getRegistryImpl(classname, classSecurityToken); // Make sure there is a Registry; if (impl.getRegistry() == null) { impl.setRegistry(new Registry(impl)); } return impl; } } /** * Constructor to create a new Registry with a RegistryImpl * and to insert it int the list of known Registry instances. * @param impl the RegistryImpl to delegate to */ private Registry(RegistryImpl impl) { this.impl = impl; } /** * Gets the content handler server registered for the content * handler. * The <code>classname</code> MUST be registered as * a content handler in the current application package using * either the {@link #register register} method or * the static registration attributes. * * @param classname the name of an application class or * content handler registered by this application package * @return the content handler for the registered * <code>classname</code> registered by this application package; * MUST NOT be <code>null</code> * * @exception NullPointerException if <code>classname</code> is * <code>null</code> * @exception ContentHandlerException is thrown with a reason of * <code>NO_REGISTERED_HANDLER</code> if there is no * content handler registered for the classname in the current * application package */ public static ContentHandlerServer getServer(String classname) throws ContentHandlerException { RegistryImpl registryImpl = findRegistryImpl(classname); // Insure only one thread promotes to ContentHandlerServer ContentHandlerImpl server = null; synchronized (mutex) { server = registryImpl.getServer(); if (server == null) { throw new ContentHandlerException("No registered handler", ContentHandlerException.NO_REGISTERED_HANDLER); } if (!(server instanceof ContentHandlerServer)) { // Not already a ContentHandlerServer; replace server = new ContentHandlerServerImpl(server); registryImpl.setServer(server); } } return (ContentHandlerServer)server; } /** * Registers the application class using content * type(s), suffix(es), and action(s), action name(s), * access restrictions and content handler ID. * <p> * This method will replace any content handler * registration in the application package * that has the same classname. * The update occurs atomically: the update to the registry * either occurs or it does not. * <p> * The content handler may register the following items: * <ul> * <li>zero or more content types</li> * <li>zero or more suffixes</li> * <li>zero or more actions</li> * <li>zero or more mappings from actions to action names</li> * <li>zero or more IDs of applications allowed access </li> * <li>an optional application ID</li> * </ul> * * <p> * If no exceptions are thrown, then the type(s), suffix(s), action(s), * action names, access restrictions, and ID * will be registered for the application class. * <p> * If an exception is thrown, then the previous registration, if * any, will not be removed or modified. * * @param classname the name of an application class or * content handler in this application package; * the value MUST NOT be <code>null</code>; * and the handler MUST implement the lifecycle of the Java runtime * environment * @param types an array of types to register; * if <code>null</code> it is treated the same as an empty array * @param suffixes an array of suffixes to register; * if <code>null</code> it is treated the same as an empty array * @param actions an array of actions to register; * if <code>null</code> it is treated the same as an empty array * @param actionnames an array of ActionNameMaps to register; * if <code>null</code> it is treated the same as an empty array * @param ID the content handler ID; if <code>null</code> * a default non-null value MUST be provided by the implementation * @param accessAllowed the IDs of applications and content * handlers that are * allowed visibility and access to this content handler; * if <code>null</code> or an empty array then all applications and * content handlers are allowed access; * otherwise ONLY applications and content handlers with matching IDs * are allowed access. * * @return the registered ContentHandler; MUST NOT be <code>null</code> * @exception NullPointerException if any of the following items is * <code>null</code>: * <ul> * <li><code>classname</code></li> * <li>any array element of <code>types</code>, <code>suffixes</code>, * <code>actions</code>, <code>actionnames</code>, and * <code>accessAllowed</code></li> * </ul> * * @exception IllegalArgumentException is thrown: * <ul> * <li>if any of the <code>types</code>, <code>suffix</code>, * <code>actions</code>, or <code>accessAllowed</code> * strings have a length of zero, or </li> * <li>if the <code>classname</code> does not implement the valid * lifecycle for the Java runtime environment,</li> * <li>if the ID has a length of zero or contains any * control character or space (U+0000-U+00020),</li> * <li>if the sequence of actions in any ActionNameMap * is not the same as the sequence of <code>actions</code>, * or </li> * <li>if the locales of the ActionNameMaps are not unique.</li> * </ul> * @exception ClassNotFoundException if the <code>classname</code> * is not present * @exception ContentHandlerException with an error code of * {@link ContentHandlerException#AMBIGUOUS} if <code>ID</code> * (or if ID is null, the default ID) * is a prefix of any registered handler or if any registered * handler ID is a prefix of this ID, * except where the registration is replacing or updating * an existing registration with the same <code>classname</code> * * @exception SecurityException if registration * is not permitted */ public ContentHandlerServer register(String classname, String[] types, String[] suffixes, String[] actions, ActionNameMap[] actionnames, String ID, String[] accessAllowed) throws SecurityException, IllegalArgumentException, ClassNotFoundException, ContentHandlerException { // First register the new/replacement handler impl.register(classname, types, suffixes, actions, actionnames, ID, accessAllowed); // Return the value from {#link #getServer(classname)}. return getServer(classname); } /** * Removes the content handler registration for the application * class and any bindings made during registration to the content ID, * type(s), suffix(es), and action(s), etc. * Only content handlers registered either statically or dynamically * in the current application package will be removed. * * @param classname the name of the content handler class * @return <code>true</code> if the content handler registered * by this application was found and removed; * <code>false</code> otherwise * @exception NullPointerException if <code>classname</code> is * <code>null</code> */ public boolean unregister(String classname) { return impl.unregister(classname); } /** * Gets all of the unique content types for which there are registered * handlers. * Type strings are not case sensitive, types that differ * only by case are treated as a single type. * Each type is returned only once. * After a successful registration, the content handler's type(s), * if any, will appear in this list. * <P> * Only content handlers that this application is * allowed to access will be included.</p> * * @return an array of types; MUST NOT be <code>null</code> */ public String[] getTypes() { return impl.getTypes(); } /** * Gets the IDs of the registered content handlers. * <P> * Only content handlers that this application is * allowed to access will be included.</p> * @return an array of content handler IDs; * MUST NOT be <code>null</code> */ public String[] getIDs() { return impl.getIDs(); } /** * Gets the unique actions of the registered content handlers. * No duplicate strings will be returned. * After a successful registration the content handler's action(s), * if any, will appear in this list. * <P> * Only content handlers that this application is * allowed to access will be included.</p> * @return an array of content handler actions; * MUST NOT be <code>null</code> */ public String[] getActions() { return impl.getActions(); } /** * Gets the unique suffixes of the registered content handlers. * Suffix strings are not case sensitive, suffixes that differ * only by case are treated as a single suffix. * Each suffix is returned only once. * After a successful registration the content handler's suffix(es), * if any, will appear in this list. * <P> * Only content handlers that this application is * allowed to access will be included.</p> * @return an array of content handler suffixes; * MUST NOT be <code>null</code> */ public String[] getSuffixes() { return impl.getSuffixes(); } /** * Gets the registered content handlers for the content type. * <P> * Only content handlers that are visible and accessible to this * application are returned. * * @param type the type of the requested content handlers * @return an array of the <code>ContentHandler</code>s registered * for the type; MUST NOT be <code>null</code>. * An empty array is returned if there are no * <code>ContentHandler</code>s accessible to * this application with the type equal to the request type. * @exception NullPointerException if <code>type</code> is * <code>null</code> */ public ContentHandler[] forType(String type) { return impl.forType(type); } /** * Gets the registered content handlers that support the action. * <P> * Only content handlers that are visible and accessible to this * application are returned. * * @param action content handlers for which the action is supported * @return an array of the <code>ContentHandler</code>s registered * for the action; MUST NOT be <code>null</code>; * an empty array is returned if no <code>ContentHandler</code>s * are accessible to this application * @exception NullPointerException if <code>action</code> is * <code>null</code> */ public ContentHandler[] forAction(String action) { return impl.forAction(action); } /** * Gets the content handlers for the suffix. * <p> * Only content handlers that are visible and accessible to this * application are returned. * * @param suffix the suffix to be used to get the associated * content handlers * * @return an array of the <code>ContentHandler</code>s registered * for the suffix; MUST NOT be <code>null</code>. * An empty array is returned if there are none accessible to * this application * * @exception NullPointerException if <code>suffix</code> is * <code>null</code> */ public ContentHandler[] forSuffix(String suffix) { return impl.forSuffix(suffix); } /** * Gets the registered content handler for the ID. * The query can be for an exact match or for the handler * matching the prefix of the requested ID. * <P> * Only a content handler which is visible to and accessible to this * application will be returned. * <P> * The <code>forID</code> method may be useful for applications * with multiple components or subsystems * to define a base ID for the application. * A request to a particular component can be made by appending an * additional string to the base ID. The additional string can be * used by the handler itself to dispatch to * the component or subsystem. The <code>forID</code> method can be used to * query for the registered content handler. * * @param ID the content handler application ID of the content * handler requested * @param exact <code>true</code> to require an exact match; * <code>false</code> to allow a registered content handler ID * to match a prefix of the requested ID * * @return the content handler that matches the ID, * otherwise <code>null</code> * * @exception NullPointerException if <code>ID</code> is * <code>null</code> */ public ContentHandler forID(String ID, boolean exact) { return impl.forID(ID, exact); } /** * Gets the registered content handlers that could be used for * this Invocation. Only handlers accessible to the application * are considered. The values for ID, type, URL, and * action are used in the following order: * <ul> * <li>If the ID is non-null, then a candidate * handler is determined by the {@link #forID forID} * method with the parameter <tt>exact</tt> set to false. * The type and URL are ignored. If there is no handler that matches * the requested ID then a <tt>ContentHandlerException</tt> * is thrown.</li> * * <li>If the ID and type are <code>null</code> and * the URL is <code>non-null</code> and * if the protocol supports typing of content, then * the type is determined * as described in {@link Invocation#findType}. * If the type cannot be determined from the content, * the type is set to <code>null</code>.</li> * * <li>If the ID is null and type is non-null, * then the set of candidate handlers is determined from the * {@link #forType forType} method. * If there are no handlers that match the requested type * then a <tt>ContentHandlerException</tt> is thrown. </li> * * <li>If both the ID and type are <code>null</code> and * the URL is <code>non-null</code> and * if the protocol does not support typing of content * or the type was not available from the content, * then the set of candidate handlers * includes any handler with a suffix that matches the * end of the path component of the URL. * If there are no handlers that match a registered * suffix then a <tt>ContentHandlerException</tt> is thrown.</li> * * <li>If the ID, type, and URL are all null, the set of candidate * handlers includes all of the accessible handlers.</li> * * <li>If the action is non-null, the set of candidate handlers * is reduced to contain only handlers that support the * action.</li> * * <li>If the set of candidate handlers is empty * then a <tt>ContentHandlerException</tt> is thrown.</li> * </ul> * <p> * The calling thread blocks while the ID and type are being determined. * If a network access is needed there may be an associated delay. * * @param invocation the ID, type, action, and URL that * are needed to identify one or more content handlers; * must not be <code>null</code> * @return an array of the <code>ContentHandler</code>(s) * that could be used for this Invocation; MUST NOT be <code>null</code>; * * @exception IOException is thrown if access to the content fails * @exception ContentHandlerException is thrown with a reason of * <code>NO_REGISTERED_HANDLER</code> if * there is no registered content handler that * matches the requested ID, type, URL, and action * * @exception IllegalArgumentException is thrown if ID, type, URL, * and action are all <code>null</code> or * if the content is accessed via the URL and the URL is invalid * @exception NullPointerException is thrown if the * <code>invocation</code> is <code>null</code> * @exception SecurityException is thrown if access to the content * is not permitted */ public ContentHandler[] findHandler(Invocation invocation) throws IOException, ContentHandlerException, SecurityException { return impl.findHandler(invocation.getInvocImpl()); } /** * Checks the Invocation and uses the ID, type, URL, and action, * if present, to find a matching ContentHandler and queues this * request to it. * <p> * If the <code>previous</code> Invocation is <code>null</code>, then * a new transaction is created; otherwise, this * Invocation will use the same transaction as the * <code>previous</code> Invocation. * <p> * The status of this Invocation MUST be <code>INIT</code>. * If there is a previous Invocation, that Invocation MUST * have a status of <code>ACTIVE</code> and this Invocation MUST * require a response. * <p> * Candidate content handlers are found as described in * {@link #findHandler findHandler}. If any handlers are * found, one is selected for this Invocation. * The choice of content handler is implementation dependent. * <p> * A copy of the Invocation is made, the status is set to * <code>ACTIVE</code> and then queued to the * target content handler. * If the invoked content handler is not running, it MUST be started * as described in <a href="#execution">Invoking a Content Handler</a>. * <p> * The status of this Invocation is set to <code>WAITING</code>. * If there is a non-null <code>previous</code> Invocation, * its status is set to <code>HOLD</code>. * The <code>previous</code> Invocation is saved in the waiting * Invocation. * It can be retrieved by the <code>getPrevious</code> method. * <p> * The calling thread blocks while the content handler is being determined. * If a network access is needed, there may be an associated delay. * * @param invocation the Invocation containing the target ID, type, URL, * actions, arguments, and responseRequired parameters; * MUST NOT be <code>null</code> * @param previous a previous Invocation for this Invocation; * may be <code>null</code> * * @return <code>true</code> if the application MUST * voluntarily exit to allow the target content handler to be started; * <code>false</code> otherwise * * @exception IllegalArgumentException is thrown if: * <ul> * <li> the ID, type, URL, and action are all * <code>null</code>,</li> * <li> the argument array contains any <code>null</code> * references, or <li> * <li> the content is accessed via the URL and the URL is * invalid, or * <li> the <code>invocation.getResponseRequired</code> * method returns <code>false</code> and * <code>previous</code> is non-null</li> * </ul> * @exception IOException is thrown if access to the content fails * @exception ContentHandlerException is thrown with a reason of * <code>NO_REGISTERED_HANDLER</code> if * there is no registered content handler that * matches the requested ID, type, URL, and action * * @exception IllegalStateException is thrown if the status of this * Invocation is not <code>INIT</code> or if the status of the previous * Invocation, if any, is not <code>ACTIVE</code> * @exception NullPointerException is thrown if the * <code>invocation</code> is <code>null</code> * @exception SecurityException if access to the content is not permitted */ public boolean invoke(Invocation invocation, Invocation previous) throws IllegalArgumentException, IOException, ContentHandlerException, SecurityException { if (invocation.getStatus() != Invocation.INIT) { throw new IllegalStateException(); } if (previous != null && previous.getStatus() != Invocation.ACTIVE) { throw new IllegalStateException(); } InvocationImpl invocImpl = invocation.getInvocImpl(); InvocationImpl prevImpl = null; if (previous != null) { prevImpl = previous.getInvocImpl(); } return impl.invoke(invocImpl, prevImpl); } /** * Checks the Invocation and uses the ID, type, URL, and action, * if present, to find a matching ContentHandler and queues this * request to it. * The behavior is identical to * <code>invoke(invocation, null)</code>. * * @param invocation the Invocation containing the target ID, type, * URL, action, arguments, and responseRequired parameters; * MUST NOT be <code>null</code> * * @return <code>true</code> if the application MUST * voluntarily exit to allow the target content handler to be started; * <code>false</code> otherwise * * @exception IllegalArgumentException is thrown if: * <ul> * <li> the ID, type, URL, and action are all * <code>null</code>, or </li> * <li> the content is accessed via the URL and the URL is * invalid, or * <li> the argument array contains any <code>null</code> * references</li> * </ul> * @exception IOException is thrown if access to the content fails * @exception ContentHandlerException is thrown with a reason of * <code>NO_REGISTERED_HANDLER</code> if * there is no registered content handler that * matches the requested ID, type, URL, and action * * @exception IllegalStateException is thrown if the status of this * Invocation is not <code>INIT</code> * @exception NullPointerException is thrown if the * <code>invocation</code> is <code>null</code> * @exception SecurityException if access to the content is not permitted */ public boolean invoke(Invocation invocation) throws IllegalArgumentException, IOException, ContentHandlerException, SecurityException { return invoke(invocation, null); } /** * Reinvokes the Invocation and uses the ID, type, URL, and action * to find a matching ContentHandler and re-queues this request to * it. Reinvocation is used to delegate the handling of an active * Invocation to another content handler. * The processing of the Invocation instance is complete and the * status is set to <code>OK</code>. Responses to the * reinvocation will be queued to the original invoking * application, if a response is required. * * <p> * The status of this Invocation MUST be <code>ACTIVE</code>. * <p> * Candidate content handlers are found as described in * {@link #findHandler findHandler}. If any handlers are * found, one is selected for this Invocation. * The choice of content handler is implementation dependent. * <p> * The status of this Invocation is set to <code>OK</code>. * A copy of the Invocation is made, the status is set to * <code>ACTIVE</code>, and then queued to the * target content handler. * If the invoked content handler application is not running, * it MUST be started * as described in <a href="#execution">Invocation Processing</a>. * * <p> * The calling thread blocks while the content handler is being determined. * If a network access is needed there may be an associated delay. * * @param invocation an Invocation containing the target ID, type, * action, arguments, and responseRequired parameters; * MUST NOT be <code>null</code> * * @return <code>true</code> if the application MUST * voluntarily exit to allow the target content handler to be started; * <code>false</code> otherwise * * @exception IllegalArgumentException is thrown if: * <ul> * <li> the ID, type, and URL are all <code>null</code>, or </li> * <li> the content is accessed via the URL and the URL is * invalid, or * <li> the argument array contains any <code>null</code> * references</li> * </ul> * @exception IOException is thrown if access to the content fails * @exception ContentHandlerException is thrown with a reason of: * <code>NO_REGISTERED_HANDLER</code> if * there is no registered content handler that * matches the requested ID, type, URL, and action * * @exception IllegalStateException is thrown if the status of this * Invocation is not <code>ACTIVE</code> * @exception NullPointerException is thrown if the * <code>invocation</code> is <code>null</code> * @exception SecurityException if access to the content is not permitted */ public boolean reinvoke(Invocation invocation) throws IllegalArgumentException, IOException, ContentHandlerException, SecurityException { if (invocation.getStatus() != Invocation.ACTIVE) { throw new IllegalStateException(); } return impl.reinvoke(invocation.getInvocImpl()); } /** * Gets the next Invocation response pending for this application. * If requested, the method waits until an Invocation response * is available. * The method can be unblocked with a call to * {@link #cancelGetResponse cancelGetResponse}. * The application can process the Invocation based on * its status. The status is one of * <code>OK</code>, <code>CANCELLED</code>, <code>ERROR</code>, * or <code>INITIATED</code>. * <p> * If the Invocation was invoked with * {@link #invoke(Invocation invocation, Invocation previous)}, * the <code>getPrevious</code> method MUST return the * previous Invocation. * If the status of the previous Invocation is <code>HOLD</code> * then its status is restored to <code>ACTIVE</code>. * * <p> * If the original Invocation instance is reachable, then it * MUST be updated with the values from the response * and be returned to the application. If it is not * reachable, then a new instance is returned from * <code>getResponse</code> with the response values. * * @param wait <code>true</code> if the method * MUST wait for an Invocation if one is not available; * otherwise <code>false</code> if the method MUST NOT wait * * @return the next pending response Invocation or <code>null</code> * if the <code>wait</code> is false and no Invocation is available or * if canceled with {@link #cancelGetResponse} * @see #invoke * @see #cancelGetResponse */ public Invocation getResponse(boolean wait) { return impl.getResponse(wait); } /** * Cancels a pending <code>getResponse</code>. * This method will force a thread blocked in a call to the * <code>getResponse</code> method for this Registry instance * to return early. * If no thread is blocked; this call has no effect. */ public void cancelGetResponse() { impl.cancelGetResponse(); } /** * Sets the listener to be notified when a new response is * available for the application context. The request must * be retrieved using {@link #getResponse getResponse}. * If the listener is <code>non-null</code> and a response is * available, the listener MUST be notified. * <br> * Note that if <tt>getResponse</tt> is being called concurrently * with the listener then the listener may not be called because * the response has already been returned to the application. * The <tt>invocationResponseNotify</tt> is only used as a hint that * a response may be available. * * @param listener the listener to register; * <code>null</code> to remove the listener */ public void setListener(ResponseListener listener) { impl.setListener(listener); } /** * Gets the content handler ID for the current application. * The ID uniquely identifies the content handler. * If the application is a content handler as returned from * {@link #getServer getServer} then the ID MUST be * the content handler ID returned from * {@link ContentHandlerServer#getID ContentHandlerServer.getID}. * Otherwise, the ID will be generated for the profile. * The package documentation * for "Content Handlers and the Mobile Information Device Profile" * defines the value for MIDP. * @return the ID; MUST NOT be <code>null</code> */ public String getID() { return impl==null? null : impl.getID(); } }