RegistryImplpublic final class RegistryImpl extends Object Implementation of Content Handler registry. It maintains
the set of currently registered handlers and updates to
the file that holds the permanent set.
The RegistryImpl class maintains an array of the current
registrations that is initialized on first use. |
Fields Summary |
---|
private static com.sun.midp.security.SecurityToken | classSecurityTokenThis class has a different security domain than the MIDlet suite | private final Hashtable | activeInvocationsThe set of active Invocations. | private static Hashtable | registriesThe set of active RegistryImpls. | private static final Object | mutexThe mutex used to avoid corruption between threads. | private ResponseListenerImpl | listenerImplImplementation of the listener. | private ContentHandlerImpl | handlerImplThe ContentHandlerImpl that matches the classname of this Registry. | private Registry | registryThe Registry that is delegating to this RegistryImpl. | final AppProxy | applicationThe AppProxy for this registry. | int | responseCallsCount of responses received. |
Constructors Summary |
---|
private RegistryImpl(String classname)RegistryImpl constructor and insert the instance in the
list of registered applications.
try {
// Get the application for the class
application = AppProxy.getCurrent().forClass(classname);
} catch (ClassNotFoundException cnfe) {
throw new ContentHandlerException("not an application",
ContentHandlerException.NO_REGISTERED_HANDLER);
} catch (IllegalArgumentException iae) {
throw new ContentHandlerException("not an application",
ContentHandlerException.NO_REGISTERED_HANDLER);
}
/* Remember the ContentHandlerImpl, if there is one. */
handlerImpl = getServer(application);
if (handlerImpl == null && (!application.isRegistered())) {
// Classname is not a registered MIDlet or ContentHandler; fail
throw new ContentHandlerException("not a registered MIDlet",
ContentHandlerException.NO_REGISTERED_HANDLER);
}
|
Methods Summary |
---|
public void | cancelGetResponse()Cancels a pending getResponse .
This method will force a Thread blocked in a call to the
getResponse method for the same application
context to return early.
If no Thread is blocked; this call has no effect.
InvocationStore.cancel();
| static ContentHandlerImpl | checkConflicts(ContentHandlerImpl handler)Check for conflicts between a proposed new handler and the existing
handlers. If the handler is being replaced it will be returned.
Locate and return any existing handler for the same classname.
ContentHandlerImpl[] handlers = RegistryStore.findConflicted(handler.ID);
ContentHandlerImpl existing = null;
if (handlers != null) {
switch (handlers.length) {
case 0:
break;
case 1:
if (handler.classname.equals(handlers[0].classname)) {
existing = handlers[0];
break;
}
default:
throw new ContentHandlerException(
"ID would be ambiguous: " + handler.ID,
ContentHandlerException.AMBIGUOUS);
}
}
if (existing == null) {
existing = RegistryStore.getHandler(handler.storageId, handler.classname);
}
return existing;
| static void | cleanup(int suiteId, java.lang.String classname)Cleanup as necessary for this classname, both for ContentHandlerServer
and the registry.
Cleanup is required by the fault handling descriptions in
{@link javax.microedition.content.ContentHandlerServer}.
-
If an Invocation with a status of
ACTIVE is dequeued by
the content handler, but the handler does not call
{@link javax.microedition.content.ContentHandlerServer#finish finish}
or make a request to chain a new Invocation to the ACTIVE
invocation before the content handler exits, then the AMS MUST
complete the request with an ERROR status.
-
If the content handler is not running, or exits before processing
all queued requests or responses, then it MUST be started.
The content handler is expected to dequeue at least one
invocation that was queued before it was started.
If it does not dequeue any pending Invocations, then Invocations
that were in the queue for the content handler
before it was started MUST be handled as follows:
- Invocation requests with a status of
ACTIVE
are completed with the ERROR status.
- Invocation responses are discarded.
- Invocations queued after the content handler was started are
retained and will require it to be restarted.
InvocationImpl invoc = null;
while ((invoc =
InvocationStore.getCleanup(suiteId, classname)) != null) {
invoc.setStatus(Invocation.ERROR);
}
| public ContentHandler[] | findHandler(InvocationImpl invoc)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:
- If the ID is non-null, then the set of candidate
handlers is determined from the {@link #forID forID}
method with the parameter exact set to false.
If there is an exact match it MUST be returned as
the first handler.
The type and URL are ignored. If there are no handlers that match
the requested ID then a ContentHandlerException
is thrown.
- If the ID and type are
null and
the URL is non-null 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 null .
- 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 ContentHandlerException is thrown.
- If both the ID and type are
null and
the URL is non-null 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 ContentHandlerException is thrown.
- If the ID, type, and URL are all null, the set of candidate
handlers includes all of the accessible handlers.
- If the action is non-null, the set of candidate handlers
is reduced to contain only handlers that support the
action.
- If the set of candidate handlers is empty
then a ContentHandlerException is thrown.
The calling thread blocks while the ID and type are being determined.
If a network access is needed there may be an associated delay.
ContentHandler[] handlers = null;
if (invoc.getID() != null) {
ContentHandler handler = forID(invoc.getID(), false);
if (handler != null) {
handlers = new ContentHandler[1];
handlers[0] = handler;
}
} else {
String action = invoc.getAction();
// ID is null
synchronized (mutex) {
// Inhibit types change while doing lookups
if (invoc.getType() == null &&
invoc.getURL() != null) {
try {
invoc.findType();
} catch (ContentHandlerException che) {
// Type is null
}
}
if (invoc.getType() != null) {
// The type is known; lookup the handlers
handlers = forType(invoc.getType());
} else if (invoc.getURL() != null) {
/**
* Call platform specific function for
* getting handler by URL
*/
ContentHandler suitable =
RegistryStore.getByURL(getID(), invoc.getURL(), action);
if (suitable != null) {
handlers = new ContentHandler[1];
handlers[0] = suitable;
}
} else if (action != null) {
handlers = forAction(action);
action = null;
} else {
throw new IllegalArgumentException(
"not ID, type, URL, or action");
}
// Set of candidate handlers; check for matching action
if (handlers != null && action != null) {
int rem = 0; // number of handlers to remove
for (int i = 0; i < handlers.length; i++) {
if (!handlers[i].hasAction(action)) {
handlers[i] = null;
rem++;
}
}
if (rem > 0) {
int newsz = handlers.length - rem;
if (newsz > 0) {
ContentHandler[] newhand =
new ContentHandler[newsz];
int j;
int k;
for (j = k = 0; j < newsz; j++) {
while (handlers[k] == null) {
k++;
}
newhand[j] = handlers[k++];
}
handlers = newhand;
} else {
handlers = null;
}
}
}
}
}
if (handlers == null || handlers.length == 0) {
throw new ContentHandlerException("no registered handler",
ContentHandlerException.NO_REGISTERED_HANDLER);
}
return handlers;
| public ContentHandler[] | forAction(java.lang.String action)Gets the registered content handlers that support the action.
Only content handlers that are visible and accessible to this
application are returned.
return RegistryStore.findHandler(getID(), RegistryStore.FIELD_ACTIONS,
action);
| public ContentHandler | forID(java.lang.String ID, boolean exact)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.
Only a content handler which is visible to and accessible to this
application will be returned.
return RegistryStore.getHandler(getID(), ID,
exact? RegistryStore.SEARCH_EXACT: RegistryStore.SEARCH_PREFIX);
| public ContentHandler[] | forSuffix(java.lang.String suffix)Gets all of the content handlers for the suffix.
Only content handlers that are visible and accessible to this
application are returned.
return RegistryStore.findHandler(getID(), RegistryStore.FIELD_SUFFIXES,
suffix);
| public ContentHandler[] | forType(java.lang.String type)Gets the registered content handlers for the content type.
Only content handlers that are visible and accessible to this
application are returned.
return RegistryStore.findHandler(getID(), RegistryStore.FIELD_TYPES,
type);
| public java.lang.String[] | getActions()Gets all of the actions of the registered content handlers.
After a successful registration the content handler's action(s),
if any, will appear in this list.
Only content handlers that this application is
allowed to access will be included.
return RegistryStore.getValues(getID(), RegistryStore.FIELD_ACTIONS);
| public java.lang.String | getID()Gets the content handler ID for the current application.
The ID uniquely identifies the application which contains the
content handler.
The application ID is assigned when the application is installed.
If the application is a content handler then the ID must be
the content handler ID.
return (handlerImpl != null) ?
handlerImpl.getID() : application.getApplicationID();
| public java.lang.String[] | getIDs()Gets all of the IDs of the registered content handlers.
Only content handlers that this application is
allowed to access will be included.
return RegistryStore.getValues(getID(), RegistryStore.FIELD_ID);
| public Registry | getRegistry()Gets the Registry that is delegating to this RegistryImpl.
return registry;
| public static com.sun.midp.content.RegistryImpl | getRegistryImpl(java.lang.String classname, java.lang.Object token)Gets the RegistryImpl for the application class.
The SecurityToken is needed to call from the public API package.
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.
For a MIDP implementation,
application classes must be registered with the
MIDlet-<n> attribute; content handlers are
registered with the MicroEdition-Handler-<n>
attribute or the {@link #register register} method.
When the RegistryImpl is created (the first time) all of the
existing Invocations are marked. They will be subject to
{@link #cleanup} when the MIDlet exits.
AppProxy.checkAPIPermission(token);
return getRegistryImpl(classname);
| static com.sun.midp.content.RegistryImpl | getRegistryImpl(java.lang.String classname)Gets the RegistryImpl for the application class.
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.
For a MIDP implementation,
application classes must be registered with the
MIDlet-<n> attribute; content handlers are
registered with the MicroEdition-Handler-<n>
attribute or the {@link #register register} method.
When the RegistryImpl is created (the first time) all of the
existing Invocations are marked. They will be subject to
{@link #cleanup} when the MIDlet exits.
// Synchronize between competing operations
RegistryImpl curr = null;
synchronized (mutex) {
// Check if class already has a RegistryImpl
curr = (RegistryImpl)registries.get(classname);
if (curr != null) {
// Check that it is still a CH or MIDlet
if (curr.handlerImpl == null &&
(!curr.application.isRegistered())) {
// Classname is not a registered MIDlet or ContentHandler
throw new
ContentHandlerException("not a registered MIDlet",
ContentHandlerException.NO_REGISTERED_HANDLER);
}
return curr;
}
// Create a new instance and insert it into the list
curr = new RegistryImpl(classname);
registries.put(classname, curr);
}
/*
* Unsynchronized, a new RegistryImpl has been created.
* Mark any existing Invocations so that at cleanup the pre-existing
* Invocations can be handled properly.
*/
InvocationStore.setCleanup(curr.application.getStorageId(),
classname, true);
return curr;
| public Invocation | getResponse(boolean wait, InvocationImpl resp)Gets the next Invocation response pending for this application.
The method blocks until an Invocation response is available, but
not for longer than the timeout period.
The method can be unblocked with a call to
{@link #cancelGetResponse}.
The application can process the Invocation based on
its status. The status is one of
OK , CANCELLED , or ERROR .
If the Invocation was invoked with
{@link #invoke(InvocationImpl invocation, InvocationImpl
previous)},
the getPrevious method MUST return the
previous Invocation.
If the status of the previous Invocation is HOLD
then its status is restored to ACTIVE .
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 getResponse
with the response values.
// Application has tried to get a response; reset cleanup flags on all
if (responseCalls == 0) {
InvocationStore.setCleanup(application.getStorageId(),
application.getClassname(), false);
}
responseCalls++;
// Find a response for this application and context
InvocationImpl invoc =
InvocationStore.getResponse(resp, application.getStorageId(),
application.getClassname(), wait);
if (invoc != null) {
// Keep track of how many responses have been recevied;
/*
* If there was a previous Request/Tid
* find or create the previous Invocation
* and update its state.
*/
InvocationImpl existing = removeActive(invoc);
if (existing != null) {
/*
* Copy mutable fields to the existing Invocation
* Continue with the pre-existing Invocation
*/
existing.ID = invoc.ID;
existing.arguments = invoc.arguments;
existing.data = invoc.data;
existing.url = invoc.url;
existing.type = invoc.type;
existing.action = invoc.action;
existing.status = invoc.status;
invoc = existing;
} else {
// If there is a previousTid then restore the previous
if (invoc.previousTid != 0) {
/*
* There will be a previous Invocation unless the app has
* already finished it. It will have a HOLD status.
*/
invoc.previous =
InvocationStore.getByTid(invoc.previousTid, 0);
}
}
if (invoc.previous != null &&
invoc.previous.status == Invocation.HOLD) {
// Restore ACTIVE status to a previously HELD Invocation
invoc.previous.setStatus(Invocation.ACTIVE);
}
// Make an attempt to gain the foreground
if (invoc.invokingSuiteId != MIDletSuite.UNUSED_SUITE_ID &&
invoc.invokingClassname != null) {
// Strong FG transition requested
application.requestForeground(invoc.invokingSuiteId,
invoc.invokingClassname);
}
return invoc.invocation;
}
return null;
| public ContentHandlerImpl | getServer()Gets the registered content handler for the
application class of this RegistryImpl.
return handlerImpl;
| ContentHandlerImpl | getServer(AppProxy appl)Gets the content handler for the specified application class.
The classname must be a class in the current application.
synchronized (mutex) {
String classname = appl.getClassname();
int storageId = appl.getStorageId();
ContentHandlerImpl handler = RegistryStore.getHandler(storageId, classname);
if (handler != null) {
handler.appname = appl.getApplicationName();
handler.version = appl.getVersion();
handler.authority = appl.getAuthority();
}
return handler;
}
| public java.lang.String[] | getSuffixes()Gets all of the suffixes of the registered content handlers.
After a successful registration the content handler's suffix(es),
if any, will appear in this list.
Only content handlers that this application is
allowed to access will be included.
return RegistryStore.getValues(getID(), RegistryStore.FIELD_SUFFIXES);
| public java.lang.String[] | getTypes()Gets all of the content types for which there are registered
handlers.
After a successful registration, the content handler's type(s),
if any, will appear in this list.
Only content handlers that this application is
allowed to access will be included.
return RegistryStore.getValues(getID(), RegistryStore.FIELD_TYPES);
| private void | insertActive(InvocationImpl invoc)Insert an Invocation to the set of active Invocations.
Integer tid = new Integer(invoc.tid);
activeInvocations.put(tid, invoc);
| public boolean | invoke(InvocationImpl invocation, InvocationImpl previous)Checks the Invocation and uses the ID, type, URL, and action,
if present, to find a matching ContentHandler and queues this
request to it.
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 #findHandler findHandler}. If any handlers are
found, one is selected for this Invocation.
The choice of content handler is implemention dependent.
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.
synchronized (mutex) {
// Locate the content handler for this Invocation.
ContentHandlerImpl handler =
(ContentHandlerImpl)findHandler(invocation)[0];
// Fill in information about the invoking application
invocation.invokingID = getID();
invocation.invokingSuiteId = application.getStorageId();
invocation.invokingClassname = application.getClassname();
invocation.invokingAuthority = application.getAuthority();
invocation.invokingAppName = application.getApplicationName();
boolean shouldExit = invocation.invoke(previous, handler);
// Remember the invoked invocation for getResponse
insertActive(invocation);
return shouldExit;
}
| static ContentHandlerImpl | newHandler(java.lang.String classname, java.lang.String[] types, java.lang.String[] suffixes, java.lang.String[] actions, ActionNameMap[] actionnames, java.lang.String id, java.lang.String[] accessRestricted, AppProxy appl)Create and initialize a new ContentHandler server with
type(s), suffix(es), and action(s), action name(s),
access restrictions and content handler ID.
Compute the application name, ID, and version
// Default the ID if not supplied
if (id == null) {
// Generate a unique ID based on the MIDlet suite
id = appl.getDefaultID();
}
// Create a new ContentHandler instance
ContentHandlerImpl handler =
new ContentHandlerImpl(types, suffixes, actions,
actionnames, id, accessRestricted,
appl.getAuthority());
handler.classname = classname;
handler.storageId = appl.getStorageId();
handler.appname = appl.getApplicationName();
handler.version = appl.getVersion();
return handler;
| public ContentHandlerImpl | register(java.lang.String classname, java.lang.String[] types, java.lang.String[] suffixes, java.lang.String[] actions, ActionNameMap[] actionnames, java.lang.String id, java.lang.String[] accessRestricted)Registers the application class using content
type(s), suffix(es), and action(s), action name(s),
access restrictions and content handler ID.
An application can use this method to replace or update
its own registrations
that have the same classname with new information.
The update occurs atomically; the update to the registry
either occurs or it does not.
The content handler may request to the following
items:
- zero or more content types
- zero or more suffixes
- zero or more actions
- zero or more mappings from actions to action names
- zero or more access restrictions
- a optional application ID
If no exceptions are thrown, then the type(s), suffix(s), action(s),
action names, and access restrictions, and ID
will be registered for the application class.
If an exception is thrown, then the previous registration, if
any, will not be removed or modified.
application.checkRegisterPermission("register");
// May throw ClassNotFoundException or IllegalArgumentException
AppProxy appl = application.forClass(classname);
synchronized (mutex) {
// Create a new ContentHandler instance
ContentHandlerImpl handler =
newHandler(classname, types, suffixes, actions,
actionnames, id, accessRestricted, appl);
handler.registrationMethod = ContentHandlerImpl.REGISTERED_DYNAMIC;
ContentHandlerImpl conflict = checkConflicts(handler);
if (conflict != null) {
unregister(classname);
}
RegistryStore.register(handler);
setServer(handler);
if (AppProxy.LOG_INFO) {
appl.logInfo("Register: " + classname +
", id: " + handler.getID());
}
return handler;
}
| public boolean | reinvoke(InvocationImpl invocation)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 OK . Responses to the
reinvocation will be queued to the original invoking
application, if a response is required.
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.
The status of this Invocation is set to OK .
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 application 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.
synchronized (mutex) {
// Locate the content handler for this Invocation.
ContentHandlerImpl handler =
(ContentHandlerImpl)findHandler(invocation)[0];
// Save the TID in case the invoke fails
int tid = invocation.tid;
// The information about the invoking application is already set
boolean shouldExit = invocation.invoke(null, handler);
/*
* Only if the invoke succeeds can the original Invocation be
* discarded.
* Restore the tid so the correct native invoc is disposed.
*/
invocation.tid = tid;
invocation.setStatus(InvocationImpl.DISPOSE);
invocation.setStatus(Invocation.OK);
return shouldExit;
}
| private InvocationImpl | removeActive(InvocationImpl invoc)Remove an Invocation from the set of active Invocations.
Integer tid = new Integer(invoc.tid);
return (InvocationImpl)activeInvocations.remove(tid);
| public void | setListener(ResponseListener listener)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}.
// Create or update the listener implementation
synchronized (this) {
if (listener != null || listenerImpl != null) {
// Create or update the active listener thread
if (listenerImpl == null) {
listenerImpl =
new ResponseListenerImpl(this, listener);
} else {
listenerImpl.setListener(listener);
}
// If the listener thread no longer needed; clear it
if (listener == null) {
listenerImpl = null;
}
}
}
| public void | setRegistry(Registry newRegistry)Sets the Registry that is delegating to this instance.
Settable only once.
Synchronization is performed in
{@link javax.microedition.content.Registry#register}.
if (registry == null) {
registry = newRegistry;
}
| public void | setServer(ContentHandlerImpl server)Sets the ContentHandlerImpl; update any active RegistryImpl.
Replaces the entry in RegisteredTypes list as well.
synchronized (mutex) {
// Update the RegistryImpl, if any, this is a server for
RegistryImpl impl = (RegistryImpl)registries.get(server.classname);
if (impl != null) {
impl.handlerImpl = server;
}
}
| public boolean | unregister(java.lang.String classname)Removes the content handler registration for the application
class and any bindings to the content handler name, content
type(s), suffix(es), action(s), and access restrictions.
if (classname == null) {
throw new NullPointerException(
"classname argument can not be null");
}
synchronized (mutex) {
ContentHandlerImpl curr = null;
RegistryImpl reg = (RegistryImpl)registries.get(classname);
if (reg != null) {
curr = reg.getServer();
} else {
try {
curr = RegistryStore.getHandler(application.getStorageId(), classname);
} catch (IllegalArgumentException iae) {
// Empty class name falls down without further processing.
}
}
if (curr != null) {
RegistryStore.unregister(curr.getID());
int suiteId = application.getStorageId();
if (reg != null && classname.equals(curr.classname) &&
suiteId == curr.storageId) {
reg.handlerImpl = null;
}
return true;
}
}
return false;
|
|