devxlogo

Push Your MIDlets to Do a Lot More with MIDP 2.0 PushRegistry

Push Your MIDlets to Do a Lot More with MIDP 2.0 PushRegistry

he 2.0 release of MIDP includes a number of enhancements that help developers write Java applications for devices. One of the most intriguing new features is “push,” which provides a way for a MIDlet to respond to network activity regardless of whether it is currently running. Among other things, push can be used to integrate wireless messaging into applications or proactively contact the user about something of interest to them. Applications can even run as a service by responding to an inbound network connection, performing a task and then shutting down. All of this can occur with little or no user interaction.

MIDlets, in a sense, can now run like a service on a device to handle certain tasks without the user explicitly needing to start the application. With the addition of push, MIDP applications gain prominence on the device, much like SMS and the phone call features of a cell phone, rather than being tucked off to the side under some obscure menu.

In this article we’ll delve into the details of the MIDP 2.0 push features and demonstrate how the PushRegistry can be used to enhance your mobile applications.

What Are the Parts of Push?
At the heart of MIDP 2.0 push are two components: the javax.microedition.io.PushRegistry class and the Application Management Software (AMS). The PushRegistry provides the interface for managing network connections related to push. The AMS participates by monitoring network activity and starting an associated MIDlet (if it’s not already running) in response to network activity over a certain port.

What You Need
J2ME Wireless Toolkit 2.1?Available at http://java.sun.com/products/j2mewtoolkit/download-2_1.html.

Here’s how it works: A MIDlet registers a connection, such as a socket or datagram, with the PushRegistry. This can either be done statically, by specifying the connection string in the application descriptor and distributing it with the application, or dynamically, using the PushRegistry class at runtime. When the AMS detects an incoming connection associated with a MIDlet, the AMS starts the MIDlet and calls the startApp() method. At this point the MIDlet takes over responsibility for the connection and performs the steps necessary for handling the incoming connection.

If the MIDlet is already running, however, it is important to understand that the AMS does not get involved. This is because once a MIDlet is running it can listen for and handle inbound connections without AMS assistance.

On the next page I’ll discuss push registration in more detail.

Static Registration
To statically declare a push connection, a connection string must be specified in the Java Application Descriptor (JAD) file or the JAR manifest (depending on how the platform supports the application descriptor). Connections declared in the application descriptor follow the format:

MIDlet-Push-: , , 

The first element, MIDlet-Push-, simply labels the entry as a push connection. Multiple push connection entries are supported. Each entry must be numbered in sequence starting at 1. For example:

MIDlet-Push- MIDlet-Push- 

The next element, is a connection string of the type that you would pass to a Connector.open() statement, such as datagram://:444 or socket://:111. The type of connection must be supported by the device and must be available to push connections. Note that the two connection availabilities are not the same. Just because a device supports datagrams does not mean it supports datagrams in the PushRegistry. There are no explicit requirements stated by the MIDP 2.0 specification as to what types of push connections must be supported. As a result, the availability of push can vary between devices. We’ll talk about how to handle this later on in this article.

The next element is . This is where you associate a MIDlet to the inbound connection declared by . This must be a fully qualified MIDlet class name, such as com.gearworks.PushExample and the MIDlet must be declared as part of the MIDlet suite in the same application descriptor. For example, there must be a MIDlet declaration that specifies the same class, such as the following:

MIDlet-1: PushExample, PushExample.png, com.gearworks.PushExample

The name of the MIDlet is not what is important here. What’s important is the fully qualified class name that correlates the MIDlet with a connection string. Also, not just any class can be specified here, it must be a class inheriting from javax.microedition.midlet.MIDlet so that the AMS can start the MIDlet when an incoming connection is received and call the startApp() method.

The last parameter, , is a filter mechanism that provides a way to restrict incoming connections to a specific IP address, address range, or subnet. For example, the com.gearworks.PushExample MIDlet could register for datagrams pushed only from 12.23.101.02 by declaring the following connection string:

MIDlet-Push-1: datagram://:444, com.gearworks.PushExample, 12.23.101.02

To restrict inbound connections to a range of IP addresses or to a subnet, two wildcard characters may be used: “*” and “?”. The “*”matches any string, including the empty string. The “?” matches any single character. The following examples show how these wildcards may be used.

  • 12.23.???.02 (specify 3 characters at the 3rd position)
  • 12.23.*.02 (specify 0 to 3 characters at the 3rd position)
  • 12.23.???.* (specify 3 characters at the 3rd position and 0 to 3 at the 4th position )
  • 12.23.??.* (specify 2 characters at the 3rd position and 0 to 3 at the 4th position )

Dynamic Registration
Dynamic registration of push connections requires the same elements as static registration but they are specified as parameters in a call to PushRegistry.registerConnection(). The following example dynamically registers a datagram connection and is identical to the static example shown previously.

PushRegistry.registerConnection("datagram://:444", "com.gearworks.PushExample", "12.23.101.02"). 

Once an application registers a connection in the PushRegistry, the registration will remain on the device until the MIDlet suite is removed or the suite itself unregisters the connection.

Registration Is Simple, but Not so Simple
So far I’ve covered how a MIDlet can be associated with an inbound connection. The steps are rather straightforward, but there are a number of reasons why push registration can fail. When a connection is registered with a MIDlet suite it is reserved exclusively for that one suite. No other MIDlet suites will be allowed to register the same connection or open the connection using Connector.open() at runtime. An IOException is thrown at runtime if a PushRegistry conflict is detected.

The device must also support the type of connection you are registering and you must have proper security to use the connection. In these cases a ConnectionNotFoundException or SecurityException is thrown at runtime if the connection is not available or the MIDlet suite does not have proper permission to use the connection. Furthermore, static connections are registered with the PushRegistry at install time. If any of these problems are encountered during installation, the installation can fail.

There are pros and cons to registering a push connection either statically or dynamically. A static registration allows a push connection to be registered upon installation and does not require the user to run the application in order to complete the registration. However, if a conflict occurs, the application cannot be installed until the conflicting application is removed from the device. Furthermore, if an application does not have proper permission to use the PushRegistry or the connections specified, the installation can fail as well.

Dynamic registration, on the other hand, has the advantage of installing without failure. However, the user must run the application at least once to invoke the dynamic registration. Because dynamic registration is done at runtime there is more flexibility in how connections are registered. For example an application can scan for an available connection to better ensure push registration success. The following code shows how this might be accomplished, by attempting up to four different connection strings:

String base = "55";String name = "PushMIDlet";for(int ccnt=5; ccnt 

This code shows how dynamic registration can be an advantage if there is a potential for push registration conflicts. Dynamic registration also provides a way to ensure the suite installs without push registration conflicts. So, if your application can make use of push, but does not absolutely require push to be useful, you should consider registering the connection dynamically. If there is a conflict or some other registration problem, the application can still be installed and must adapt to the lack of push in certain cases. However, if your application depends on a specific push connection to be useful, registering the connection statically is a good way to go since the user is informed about problems at installation time.

The following table describes the most common ways that push registration can fail. If the condition is encountered for a statically registered connection, the installation is aborted. For dynamic registrations the response can vary and is listed in the corresponding column.

Condition

Dynamic Registration Response

Connection string syntax is not valid

An IllegalArgumentException is thrown

The device does not support the specified connection type (e.g. socket) or has not made the connection type available to push

A ConnectionNotFoundException is thrown

The connection is already registered by another MIDlet suite or there are insufficient resources to handle the registration request

An IOException is thrown

The MIDlet name specified in the push connection string is not declared in the application descriptor of the MIDlet suite

A ClassNotFoundException is thrown

The MIDlet suite does not have permission to register or use the specified connection

A SecurityException is thrown

The port specified by the connection string is reserved by the device

Undefined by the MIDP specification, but an IOException is most likely.

When connections are reserved in the PushRegistry, they are reserved for a MIDlet suite, not a single MIDlet. If a MIDlet suite defines several MIDlets, all MIDlets in the suite have access to the connections in the PushRegistry. However, the MIDlet specified in the PushRegistry with the connection is the MIDlet that is started by the AMS in response to an incoming connection notification. Once a MIDlet suite is running, the suite has complete control as to how the PushRegistry connections are used.

Handling Inbound Connections
As mentioned previously, when an application is running, the AMS assumes the application will handle all inbound connections. However, if the AMS starts a MIDlet in response to an inbound connection there are a few things you will need to know in order to handle the inbound connection.

Getting a List of Connections
When the AMS receives an inbound connection notification, the MIDlet corresponding to the registered connection is instantiated and the startApp() method is invoked. Once startApp() is invoked, the MIDlet is responsible for taking over the inbound connection. A list of connections can be obtained by calling PushRegistry.listConnections(boolean). The boolean parameter indicates if the caller is interested in all connections associated with this MIDlet suite or just the connections with input available (i.e., the input from the inbound connection that caused the AMS to start the MIDlet). This method returns an array of strings from the PushRegistry. These strings can be passed directly to Connector.open() to open the connection.

If the inbound connection is a datagram, the AMS must guarantee that the original datagram that triggered the push notification is available once the MIDlet starts. However, if additional datagrams are received by the device before the MIDlet can take over the connection, these subsequent datagrams might be lost. This behavior is platform dependent. It's important to know that you may experience different behavior for pushed datagrams on two different devices.

If the inbound connection is a socket, the AMS is responsible to get the socket connection transferred to the MIDlet. However, there is a chance that the server could timeout the socket connection before handoff occurs. For this reason it is important to write your startApp() method so that the MIDlet starts quickly and takes control of the connection as soon as possible.

As a best practice, you should consider handling network connections on a thread separate from the user interface thread. Network calls can block the user interface from redrawing or responding to user input until the call returns. In some cases having the user interface and a network connection on the same thread can cause a device to deadlock. For example, if an untrusted MIDlet attempts the make an HTTP connection, the device may need to prompt the user for permission to use this service. The connection blocks until this user permission is granted. However, if the device needs to use the same thread to prompt the user for this permission, the prompt cannot be displayed. This is because the network is blocking, waiting for the response from the user prompt. Thus, a deadlock can ensue leaving the application in a hung state.

Listing 1 provides an example of how to handle inbound datagram connections in response to a pushed datagram connection.

The code in startApp() (Listing 1) creates a DatagramHandler object to process incoming datagrams on a separate thread from the main application. There is also an init flag in place to make sure that pausing and resuming the MIDlet does not cause the code to run multiple times when you don't want it to.

Now that you have some familiarity with how to register and handle pushed connections, I'll now look at another feature of the PushRegistry that allows MIDlets to be started without direct user interaction called an Alarm.

Setting Alarms
Hidden away in the API of the PushRegistry is a simple little feature called an Alarm. An Alarm can be registered for a MIDlet suite much like a connection. The difference, however, is that the MIDlet associated with an Alarm is started at a certain point in time, rather than in response to network activity. Each MIDlet suite can register, at most, one Alarm at a time. Alarms are registered by making a call to PushRegistry.registerAlarm(). The following code registers an Alarm to start the MIDlet "PushDemo" 24 hours from now.

long day = 1000*60*60*24;long t = new Date().getTime()+day;PushRegistry.registerAlarm(  "PushDemo", t);

Some devices may not support the ability to launch an application using an Alarm. In these cases, a ConnectionNotFoundException will be thrown if the application attempts to register an alarm. Furthermore, depending on the security restrictions of the device, the user may be prompted to accept or reject the Alarm. Rejecting would abort the launch of your MIDlet. The MIDlet is not allowed to run until the user responds to the prompt.

If the MIDlet does not have permission to execute in response to an Alarm, a SecurityException may be thrown. As with connections, if the MIDlet suite is running, the AMS will ignore settings in the PushRegistry. A running suite must use a Timer and TimerTask to periodically run tasks. The PushRegistry and AMS only get involved when the MIDlet suite is not running.

Pushed to the End
In this article I've discussed two ways a MIDlet can be started by the AMS using the PushRegistry: by registering a push connection or an Alarm. It's important to remember, however, that once a MIDlet suite is running, the AMS will ignore inbound connection notifications as well as any registered alarms. It is the suite's responsibility to handle these activities while running, even if the MIDlet suite is in the paused state.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist