public class PushRegistry
extends java.lang.Object
PushRegistry
maintains a list of inbound
connections. An application can register the inbound
connections with an entry in the application descriptor
or dynamically by calling the registerConnection
method.
The connection strings are URIs that are used with
Connector.open
to open the appropriate server connection.
While an application is running and has Connections open, it is
responsible for all I/O operations associated with the inbound
connection using the appropriate Generic Connection Framework
API.
When the application is not running or the application does not have the URI
open, the application management software(AMS)
listens for inbound notification requests. When a notification arrives for a
registered application, the AMS will start the application, if necessary,
via the normal invocation of MIDlet.startApp
method.
Implementations MUST guarantee that each inbound connection successfully registered (statically or dynamically) is logically unique. The logical uniqueness is determined by using the comparison ladder scheme as defined in [RFC3986]. Implementations MUST perform at least the simple string comparison, and SHOULD perform one or more of the latter steps of the comparison ladder scheme.
To avoid collisions on inbound generic connections, the application
descriptor MUST include information about static connections
that are needed by the application
suite.
See
Provisioning for errors reported in the event of conflicts. Conditions
when the declarations can not be fulfilled include: syntax errors
in the Push attributes, declaration for a connection end point (e.g. port
number) that is already reserved in the device, declaration for a
protocol that is not supported for Push in the device, and declaration
referencing an application class that is not listed in
the MIDlet-<n>
attributes of the same
application descriptor.
If the application suite can function meaningfully even if a Push registration
can not be fulfilled, it MUST register the Push connections using
the dynamic registration with
PushRegistry.registerConnection
method.
A conflict-free installation reserves each requested connection for
the exclusive use of the applications in the suite. While the suite is
installed, any attempt by other applications to open one of the
reserved connections will fail with an IOException
.
A call from an application to Connector.open()
on a connection reserved for the application will always
succeed, assuming the application does not already have the connection open.
If two application suites have a static push connection in common, they cannot be installed together. Typically one would have to be deleted one before the other one becomes able to be successfully installed.
In some cases the application may not function properly if it cannot listen to a certain protocol or port for incoming traffic. The static push registration has been designed for these cases. The application that must have access to certain protocol or port announces this need in the application descriptor or in the JAR manifest. The implementation checks at installation time that the requested protocol or port is available and registers the application to listen to the incoming traffic. If the request cannot be fulfilled because protocol or port is already reserved, the installation of the application fails.
Static Push registrations are done in the application descriptor or in the
JAR manifest with MIDlet-Push-<n>
attribute.
Each push registration entry contains the following information :
MIDlet-Push-<n>: <ConnectionURI>,
<applicationClassName>, <AllowedSender>
where:
MIDlet-Push-<n>
=
the Push registration attribute name. Multiple push
registrations can be provided in an application
suite. The numeric value for <n>
starts from 1 and
MUST use consecutive ordinal numbers for additional entries.
The first missing entry terminates the list. Any
additional entries are ignored. ConnectionURI
= the connection string used in
Connector.open()
MIDletClassName
= the application that is responsible for
the connection. The named application MUST be registered in the
application descriptor or the JAR manifest with a
MIDlet-<n>
record. (This information is needed when
displaying messages to the user about the application when Push
connections are detected)
If the named application appears more than once in the
suite, the first matching entry is used. AllowedSender
= a designated filter that restricts which
senders are valid for launching the requested application.
The syntax and semantics of the AllowedSender
field
depend on the addressing format used for the protocol.
However, every syntax for this field MUST support using the wildcard
characters "*" and "?". The semantics of those wildcard are:
When the value of the AllowedSender
field is just the wildcard character
"*", connections will be accepted from any originating source. For Push attributes
using the datagram
and socket
URIs (if supported by the
platform), AllowedSender
field contains a numeric IP address in the
same format for IPv4 and IPv6 as used in the respective URIs (IPv6 address
including the square brackets as in the URI). It is possible to use the wildcards
also in these IP addresses, e.g. "129.70.40.*" would allow subnet resolution. The
wildcards can also be used to match address delimiters, e.g. "72.5.1*" will match
"72.5.124.161". Note that the port number is not part of the filter for
datagram
and socket
connections. In every protocol,
the AllowedSender
field MUST match with the appropriate address field
of the incoming event. The address field to use and the exact syntax and semantics
of the address depend on the protocol. However, the address and the
AllowedSender
filter MUST be compared by exact string matching where
the strings are compared character by character and the characters need to match
exactly except as allowed by the two wildcard characters: asterisk(*) and question
mark(?).
This specification defines the syntax for datagram
and
socket
inbound connections. When other specifications
define push semantics for additional connection types, they
must define the expected syntax for the filter field, as well as
the expected format for the connection URI string.
The following is a sample application descriptor entry that would reserve a stream socket at port 79 and a datagram connection at port 50000. (Port numbers are maintained by IANA and cover well-known, user-registered and dynamic port numbers) [See IANA Port Number Registry]
MIDlet-Push-1: socket://:79, com.oracle.example.SampleChat, * MIDlet-Push-2: datagram://:50000, com.oracle.example.SampleChat, * |
There are cases when defining a well known port registered with IANA is not necessary. Simple applications may just wish to exchange data using a private protocol between an application and server application.
To accommodate this type of application, a mechanism is provided to dynamically allocate a connection and to register that information, as if it was known, when the application was installed. This information can then be sent to an agent on the network to use as the mechanism to communicate with the registered application.
For instance, if a UDPDatagramConnection
is opened and a port
number was not specified, then the application is requesting a dynamic port to be
allocated from the ports that are currently available. By calling
PushRegistry.registerConnection()
method the application informs the
AMS that it is the target for inbound communication, even after the application
has been destroyed. (See application life cycle for definition of Destroyed
state). Once the application has registered the connection with
PushRegistry.registerConnection
method, the connection is listed
in the PushRegistry.listConnections(false)
return value. If the
application has an open connection to the registered connection, the AMS starts
listening to the inbound connection once the connection has been closed with
Connector.close
method. If the application is deleted from the device,
then its dynamic communication connections are unregistered automatically.
Responsibility for registered Push connections is shared between the AMS and
the application that handles the I/O operations on the inbound connection. To
prevent any data from being lost, an application is responsible for all I/O
operations on the connection from the time it calls
Connector.open()
until it calls Connection.close()
.
The AMS listens for inbound connection notifications. This MAY be handled via a native callback or polling mechanism looking for new inbound data. The AMS is responsible for enforcing the Auto Invocation And Push Registry Security and presenting notifications (if any, and if the device has graphical capabilities enabling it to do so) to the user while invoking the application suite.
The AMS is responsible for the shutdown of any running applications (if necessary) prior to the invocation of the push application.
After the AMS has started the Push application, the application is responsible for opening the connections and for all subsequent I/O operations. An application that needs to perform blocking I/O operations SHOULD use a separate thread to allow for interactive user operations. Once the application has been started and the connection has been opened, the AMS is no longer responsible for listening for Push notifications for that connection. The application is responsible for reading all inbound data.
If an application has finished with all inbound data it MAY end the connection with
Connector.close()
method. If the connection is closed, then the
AMS resumes listening for Push notifications. This avoids the loss of data
that might occur if neither the application nor the AMS was listening.
When a registered Push application is not running the AMS listens for incoming connections and launches the application as necessary. If a Push application exits and there are incoming connections, either new or unhandled, for the application, then the application MUST be started to handle the available input.
A Push application SHOULD behave in a predictable manner when handling asynchronous data via the Push mechanism. An application MAY inform the user that data has been processed. (If the application has capabilities to do so.)
When the AMS is started, it checks the list of registered connections and
begins listening for inbound communication. When a notification arrives the
AMS starts the registered application. The application then opens the connection with
Connector.open()
method to perform whatever I/O operations are
needed for the particular connection type. e.g. for a server socket the application
uses acceptAndOpen()
to get the socket connected and for a
datagram connection the application uses receive()
to read the
delivered message.
For message oriented transports the inbound message may be read by the AMS and saved for delivery to the application when it requests to read the data. For stream oriented transports the connection may be lost if the connection is not accepted before the server end of the connection request timeouts.
When an application is started in response to a registered Push connection
notification, it is platform dependent what happens to the current running
application. The application life cycle defines the expected behaviors that
an interrupted application could see from a call to destroyApp()
.
The requirements for buffering of messages are specific
to each protocol used for Push and are defined separately
for each protocol. There is no general requirement related
to buffering that would apply to all protocols. If the
implementation buffers messages, these messages MUST
be provided to the application when the application is started and it
opens the related
Connection
that it has registered for Push.
When datagram
connections are supported with Push, the
implementation MUST guarantee that when an application
registered for datagram
Push is started in response to an
incoming datagram, at least the datagram that caused the startup of the
application is buffered by the implementation and will be
available to the application when the application
opens the UDPDatagramConnection
after startup.
When socket connections are supported with Push, the
implementation MUST guarantee that when an application
registered for socket
Push is started in response to
an incoming socket
connection, this connection can
be accepted by the application by opening the
ServerSocketConnection
after startup, provided
that the connection hasn't timed out meanwhile.
Not all generic connections will be appropriate for use
as push application transport. Even if a protocol is supported
on the device as an inbound connection type, it is not required
to be enabled as a valid push mechanism. For example, a platform might
support server socket connections in an application,
but might not support inbound socket connections for push
launch capability.
A ConnectionNotFoundException
is thrown from
the registerConnection
and from the
registerAlarm
methods, when the platform
does not support that optional capability.
The registerAlarm
method MUST be supported.
Usage scenario 1:
The suite includes an application with a well known port for communication.
During the startApp
processing
a thread is launched to handle the incoming data.
Using a separate thread is the recommended practice
for avoiding conflicts between blocking I/O operations
and user interaction events. The
thread continues to receive messages until the application is destroyed.
In this sample, the descriptor includes a static push connection registration. It also includes an indication that this application requires permission to use a datagram connection for inbound push messages. (See Auto Invocation And Push Registry Security for details about application permissions.) Note: this sample is appropriate for bursts of datagrams. It is written to loop on the connection, processing received messages.
Remark: This example is not appropriate for JME Embedded Profile. Has to be replaced.
MIDlet-Name: InstantMessage, example.chat.SampleChat MIDlet-Version: 1.0 MIDlet-Vendor: Oracle Corp. MIDlet-Description: Network demonstration programs MicroEdition-Profile: MEEP-8.0 MicroEdition-Configuration: CLDC-1.8 MIDlet-1: InstantMessage, , example.chat.SampleChat, * MIDlet-Push-1: datagram://:79, example.chat.SampleChat, * MIDlet-Permission-1: javax.microedition.io.PushRegistry "datagram://" MIDlet-Permission-2: javax.microedition.io.Connector "datagram://" |
public class SampleChat extends MIDlet { // Current inbound message connection. DatagramConnection conn; // Flag to terminate the message reading thread. boolean done_reading; public void startApp() { // List of active connections. String connections[]; // Check to see if this session was started due to // inbound connection notification. connections = PushRegistry.listConnections(true); // Start an inbound message thread for available // inbound messages for the statically configured // connection in the application descriptor. for (int i=0; i < connections.length; i++) { Thread t = new Thread (new MessageHandler(connections[i])); t.start(); } ... } // Stop reading inbound messages and release the push // connection to the AMS listener. public void destroyApp(boolean conditional) { done_reading = true; if (conn != null) conn.close(); // Optionally, notify network service that we're done // with the current session. ... } // Inner class to handle inbound messages on a separate thread. class MessageHandler implements Runnable { String connUrl ; MessageHandler(String uri) { connUri = uri ; } // Fetch messages in a blocking receive loop. public void run() { try { // Get a connection handle for inbound messages // and a buffer to hold the inbound message. DatagramConnection conn = (DatagramConnection) Connector.open(connUri); Datagram data = conn.newDatagram(conn.getMaximumLength()); // Read the inbound messages while (!done_reading) { conn.receive(data); ... } } catch (IOException ioe) { ... } ... } } } |
Usage scenario 2: The suite includes an application that dynamically allocates port the first time it is started.
In this sample, the application descriptor includes an entry indicating that the application will need permission to use the datagram connection for inbound Push messages. The dynamic connection is allocated in the constructor the first time it is run. The open connection is used during this session and can be reopened in a subsequent session in response to a inbound connection notification.
MIDlet-Name: Ping Demos MIDlet-Version: 1.0 MIDlet-Vendor: Oracle Corp. MIDlet-Description: Network demonstration programs MicroEdition-Profile: MEEP-8.0 MicroEdition-Configuration: CLDC-1.8 MIDlet-1: JustCallMe, , com.oracle.SamplePing, * MIDlet-Permissions: javax.microedition.io.PushRegistry, \\ javax.microedition.io.Connector.datagramreceiver |
public class SamplePing extends MIDlet { // Name of the current application for push registration. String myName = "com.oracle.SamplePing"; // List of registered push connections. String connections[]; // Inbound datagram connection UDPDatagramConnection dconn; public SamplePing() { // Check to see if the ping connection has been registered. // This is a dynamic connection allocated on first // time execution of this application. connections = PushRegistry.listConnections(false); if (connections.length == 0) { // Request a dynamic port for out-of-band notices. // (Omitting the port number let's the system allocate // an available port number.) try { dconn = (UDPDatagramConnection) Connector.open("datagram://"); String dport = "datagram://:" + dconn.getLocalPort(); // Register the port so the application will wake up, if messages // are posted after the application exits. PushRegistry.registerConnection(dport, myName, "*"); // Post my datagram address to the network ... } catch (IOException ioe) { ... } catch (ClassNotFoundException cnfe) { ... } } public void startApp() { // Open the connection if it's not already open. if (dconn == null) { // This is not the first time this is run, because the // dconn hasn't been opened by the constructor. // Check if the startup has been due to an incoming // datagram. connections = PushRegistry.listConnections(true); if (connections.length > 0) { // There is a pending datagram that can be received. dconn = (UDPDatagramConnection) Connector.open(connections[0]); // Read the datagram Datagram d = dconn.newDatagram(dconn.getMaximumLength()); dconn.receive(d); } else { // There are not any pending datagrams, but open // the connection for later use. connections = PushRegistry.listConnections(false); if (connections.length > 0) { dconn = (UDPDatagramConnection) Connector.open(connections[0]); } } } public void destroyApp(boolean unconditional) { // Close the connection before exiting if(dconn != null){ dconn.close() dconn = null } } ... |
Modifier and Type | Method and Description |
---|---|
static java.lang.String |
getFilter(java.lang.String connection)
Retrieve the registered filter for a requested connection.
|
static java.lang.String |
getMIDlet(java.lang.String connection)
Retrieve the registered application for a requested connection.
|
static java.lang.String[] |
listConnections(boolean available)
Return a list of registered connections for the current application.
|
static long |
registerAlarm(java.lang.String app,
long time)
Register a time to launch the specified application.
|
static void |
registerConnection(java.lang.String connection,
java.lang.String app,
java.lang.String filter)
Register a dynamic connection with the
application management software.
|
static boolean |
unregisterConnection(java.lang.String connection)
Remove a dynamic connection registration.
|
public static void registerConnection(java.lang.String connection, java.lang.String app, java.lang.String filter) throws java.lang.ClassNotFoundException, java.io.IOException
While the application has opened the connection with Connector.open
, the AMS will NOT be listening for the input. The application is
responsible for the connection. If the application has not opened a
connection to the registered URI, the AMS MUST listen for input
regardless of whether the application is running or not.
The arguments for the dynamic connection registration are the same as the Push Registration Attribute used for static registrations.
connection
- the URI for the connectionapp
- class name of the app
to be launched when
new external data is available. The named app
MUST be registered in the application descriptor or the JAR
manifest with a MIDlet-<n>
record. This
parameter has
the same semantics as the MIDletClassName
in the
Push registration attribute defined in the class description.filter
- a connection URI string indicating which senders are allowed
to cause the app
to be launchedjava.lang.IllegalArgumentException
- if the connection string is null
or is not valid,
or if the filter string is null
or not validConnectionNotFoundException
- if the runtime system does not support push delivery for
the requested connection protocoljava.io.IOException
- if the connection is already registered or if there are
insufficient resources to handle the registration requestjava.lang.ClassNotFoundException
- if app
is null
or
if the app
class name can not be found
in the current application suite or if this
class is not included in any of the MIDlet-<n>
records in the application descriptor or the JAR manifestjava.lang.SecurityException
- if the app
does not have permission to
register a connectionunregisterConnection(java.lang.String)
public static boolean unregisterConnection(java.lang.String connection)
connection
- the URI for the connectiontrue
if the unregistration was successful,
false
if the connection has not been registered
or if the connection argument was null
java.lang.SecurityException
- if the connection was registered by another application suiteregisterConnection(java.lang.String, java.lang.String, java.lang.String)
public static java.lang.String[] listConnections(boolean available)
Return a list of registered connections for the current application.
The URI of every registered connection is returned from
listConnections(false)
.
The URI of every connection that has available input is returned from
listConnections(true)
. URI's of connections opened with
Connector.open(URI)
are not returned. After the Connection
is closed new input may become available and the URI will again be included
in the return of listConnections(true)
. URIs of connections
that timeout or otherwise no longer have available input are not returned
from listConnections(true)
. Due to race conditions, a call to
listConnections(true)
may return URIs that will fail to open
with Connector.open
because timeouts or other connection errors.
When the application opens the URI, the application takes over listening for input
and the AMS stops listening. The listConnections(true)
method will only see URIs with available input during the time that the
application does NOT have the connection open.
available
- if true
, only return the list of
connections ready for the handoff to the application, otherwise return
the complete list of registered connections for the current applicationpublic static java.lang.String getMIDlet(java.lang.String connection)
connection
- a registered generic connection URI stringnull
if the connection was not
registered by the current application
or if the connection argument was null
registerConnection(java.lang.String, java.lang.String, java.lang.String)
public static java.lang.String getFilter(java.lang.String connection)
connection
- a registered generic connection URI stringnull
, if the connection was not
registered by the current application
or if the connection argument was null
registerConnection(java.lang.String, java.lang.String, java.lang.String)
public static long registerAlarm(java.lang.String app, long time) throws java.lang.ClassNotFoundException, javax.microedition.io.ConnectionNotFoundException
PushRegistry
supports one outstanding wake up
time per application in the current suite. An application
is expected to use java.util.TimerTask
for notification
of time based events while the application is running.
If a wakeup time was registered and is still pending, the wakeup time will be returned, otherwise zero is returned. If the wakeup has passed then the wakeup is not longer pending and zero is returned.
app
- class name of the app
within the current
running application suite to be launched, when the
alarm time has been reached. The named application
MUST be registered in the application descriptor or the JAR
manifest with a MIDlet-<n>
record. This
parameter has
the same semantics as the MIDletClassName
in the Push
registration attribute defined above in the class description.time
- time at which the app
is to be executed in
the format returned by Date.getTime()
.
If the time is zero, or is in the past, or the app
is already running at the time
then
the app MUST not be launched.app
was scheduled to occur, in the format
returned by Date.getTime()
ConnectionNotFoundException
- if the runtime system does not support alarm based
application launchjava.lang.ClassNotFoundException
- if the
class name cannot be found in the current application
suite or if this class is not included in any of the
MIDlet-<n>
records in the application descriptor
or the JAR manifest or if the app
argument is
null
java.lang.SecurityException
- if the application does not
have permission to register an alarmDate.getTime()
,
Timer
,
TimerTask
Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved. Use of this specification is subject to license terms.