Mobility News

By Johan Karlsson

You have just developed your new cool MIDlet, the one that is going to rule the world. It runs like a well oiled machine on the emulator. But when you download and install it on your target device, the MIDlet seems to take ages to start up. Finally, you see the splash screen. Oh no! The MIDlet crashes and you get an error pop-up saying "Application Error," and the MIDlet shuts down. What happened? This is not the way you pictured it. Is there something that shows what really happened behind the scenes?

Have you been in a situation like this? Have you ever wanted to log from your MIDlet? Read on, and I will teach how to add powerful logging to your MIDlets.

You may have considered doing your own logging facility. But why not use an existing solution: The Microlog open-source logging library. It is based on the well known Log4j API or logging library, but has been created from the ground up with Java ME limitations in mind.

Read the full article.

By Vikram Goyal

Logging and monitoring your MIDlet in development is easy. Just print some lines on the console around critical events, and you know what is happening within your MIDlet. Integrated development environments (IDEs) such as the NetBeans IDE make this even easier by allowing you to do on-device debugging. But this is of no use to you when your MIDlet is actually being run on a client's phone.

How do you monitor your killer MIDlet? Can you receive notification if something critical happens? Can you get an SMS to attend to notifications? Of course, you can. Several APIs make this possible, and this tech tip will show you how to combine them into a single interface.

Simulate Logging Events

To simulate the various events in an actual MIDlet, I have created a simple MIDlet with a random-event generator. The random-event generator simulates activity within the MIDlet and does nothing for normal events. Because informational events in any MIDlet are more likely to occur than warning, error, or critical events, this random MIDlet takes a sliding-scale approach to generating these events. The scale is implemented in the following code:

    // now try and simulate an event within this application
    int rand = random.nextInt(19);

    if (rand > 8) { // no event that needs logging if random no < 9
      if (rand <= 13) { // info
        form.append(midlet.getInfo());
        midlet.doInfoLog("This is an information message.");
      } else if (rand <= 15) { // warn
        form.append(midlet.getWarn());
        midlet.doWarnLog("This is a warning!");
      } else if (rand <= 17) { // error
        form.append(midlet.getError());
        midlet.doErrorLog("Oh, no, an error occurred!");
      } else { // critical
        form.append(midlet.getCritical());
        midlet.doCriticalLog("The sky is falling!");
      }
  }

When you run the MIDlet and start the activity, it will cycle through a clock going from 1 to 15. This is a timer that shows the user that some activity is happening within the MIDlet. During each activity cycle, a random number is generated. As shown in the previous code, if the random number is within the prescribed ranges, it triggers the corresponding logging event. The simple events, and the ones most likely to occur, are the informational messages. The most dire events are the ones that are marked as critical, and they occur only if the random number is exactly equal to 18.

What to Log Where

I have made the assumption that informational messages are to be recorded only, perhaps, as a way for a technical team to audit if they can get their hands on the actual device if something more critical happens. Similarly, I have assumed that warning messages are to be logged to a nearby Bluetooth device, error messages to an Internet server, and critical messages to be sent by way of SMS.

Create a Logging Interface

To keep things simple, the MIDlet makes decisions on the severity of the logging messages and creates loggers based on that assumption (described in the previous section). The following code shows how these decisions are implemented:

    private void createLoggers() {
      infoLog = new RMSLogger();
      warnLog = new BluetoothLogger();
      errorLog = new InternetLogger();
      criticalLog = new SMSLogger();
  }

Each logger is an implementation of the simple Logger interface. This interface is shown in the following code:

    public interface Logger {

      public void doLog(String msg);
    }

With a single method called doLog, the interface defines a minimum contract for the implementations to follow. The actual implementations must then figure out how they will make the logging calls.

Create the Logging Implementations

Now, it is a simple method to figure out what the actual implementations will do. For example, the following code shows what the RMSLogger will do:

    package logger.impl;

    import javax.microedition.rms.RecordStore;
    import logger.Logger;

    public class RMSLogger implements Logger {

      private RecordStore rs;

      public RMSLogger() {
        try {
          rs = RecordStore.openRecordStore("Log_Store", true);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }

      public void doLog(String msg) {
        byte[] rec = msg.getBytes();
        try {
          rs.addRecord(rec, 0, rec.length);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }

As you can see, the constructor does the background work of creating or opening the record store. The doLog() method then does the heavy lifting, by writing the message to the record store.

Similarly, here is the InternetLogger code:

    package logger.impl;

    import java.io.IOException;
    import java.io.OutputStream;
    import javax.microedition.io.Connector;
    import javax.microedition.io.HttpConnection;
    import logger.Logger;

    public class InternetLogger implements Logger {

      // set your destination URL here
      private String destURL = "";

      private HttpConnection conn;

      public InternetLogger() {

        try {
          conn = (HttpConnection) Connector.open(destURL);
          conn.setRequestMethod(HttpConnection.POST);
          conn.setRequestProperty(
            "Content-Type", "application/x-www-form-urlencoded");
        } catch (Exception e) {
          e.printStackTrace();
        }

      }

      public void doLog(String msg) {
        try {
          // The destination URL must be set before doLog is called.

          if(conn == null) {
            System.err.println("DEST URL is not valid.");
            return;
          }
          conn.setRequestProperty("Content-length", "" +
            ("msg=" + msg).getBytes().length);

          OutputStream os = conn.openOutputStream();
          os.write(("msg=" + msg).getBytes());
          os.flush();

        } catch (IOException ex) {
          ex.printStackTrace();
        }
      }
    }

The code here is just a placeholder, and you will need to fill in the destination URL where you want the message to be posted, along with some sort of identification of the sender of the message.

BluetoothLogger and SMSLogger follow similar patterns, and the source code contains the implementations for these.

Resources

By Vikram Goyal

This tip is in response to a recent discussion on the Sun forums about the thread-safety of RecordStore operations. Although the discussion goes in several different directions, the core question remains: How do you protect yourself from unsafe operations of third-party libraries?

The answer is not simple, but this tech tip will try to answer the specific example raised at the start of this discussion. Perhaps that will help provide general directions for handling such things in the real world.

RecordStore Safety

The problem boils down to individual record entry safety. The record entry method itself is atomic, recordStore.addRecord(), and therefore guaranteed to be thread-safe. However, as pointed out in the forums discussion, if consistency is measured in terms of two records being written to the record store, and if only one is entered and the second entry is interrupted because the application management software (AMS) has called destroyApp() between the two calls, have you lost a way to manage your data? Is the data now inconsistent?

Of course not.

This is where the real reason for the destroyApp() method comes into the picture, even if it is called by third-party software.

In the following code, I present the destroyApp() method that would handle this scenario consistently.

  public void destroyApp(boolean unconditional)
    throws MIDletStateChangeException {

    if(!unconditional) {
      if(!recordsWritten) { // Records have not been written yet -- wait!
        throw new MIDletStateChangeException();
      } else { // Records written -- MIDlet can be destroyed!
      }
    } else { // must destroy
      if(!recordsWritten) {
        // Roll back the record that was written.
        if(storage != null) { // Was the store ever opened?
          try {
            storage.deleteRecord(recordId1);
          } catch (Exception ex) {
            ex.printStackTrace();
          }
        }
      }
    }
  }

The destroyApp() method gives you a way to complete unfinished items before it actually closes the MIDlet. The AMS may want to close the MIDlet unconditionally, in which case, you have no choice but to close the MIDlet. But if the closing is not unconditional, and if in the middle of the writing process, you can throw the MIDletStateChangeException to finish the writing process.

Because the data is considered to be consistent only if all of it is written (in this case, two record items), you use the flag of recordsWritten to indicate this. Then you use this flag to monitor the state of the data.

If this flag is set as false, you have not finished the writing process, so you must roll back any data that has been written. It is possible that the destroyApp() method may be called before either of the records has been written. This is fair enough, and trying to delete the first record will raise an exception, which is silently ignored.

The process of writing -- and deleting -- data is itself atomic, so you can be fairly confident that data is not corrupted in between the writing processes. To further insulate from such corruption, you can synchronize on the storage object while writing or deleting.

I hope that this simple example has given you an idea on how to handle the effects of third-party libraries better. Concurrency and data safety are complex subjects, and the developer should understand the problem domain in detail before attempting specific solutions.

Resources

By Bruce Hopkins

My article Three Reasons Why Your Next Java ME Mobile Application Should Include JavaFX Mobile introduced the overall Java FX architecture and, specifically, the Java FX Mobile 1.1 APIs. Well, the JavaFX 1.2 APIs have been released since then, with tons of new features that were requested by you, the developer community.

The purpose of this tech tip is to briefly answer the questions that were submitted in the Comments section of the original article (on JavaFX 1.1), and to simultaneously point to some of the capabilities of JavaFX 1.2.

Question 1: When will development tools for JavaFX for Linux be available?

Answer: The newly released JavaFX 1.2 SDK is now available for the following four platforms:

  • Windows
  • Mac OS X
  • Linux
  • Open Solaris

Question 2: How can I load my JavaFX applications on a mobile device?

Answer: Applications created with the JavaFX 1.1 SDK were not supported on mobile devices for deployments, so it was not possible to get your JavaFX 1.1 Mobile application running on a real handset (unless you did some real hacking). However, the JavaFX 1.2 SDK is capable of creating mobile applications that can be deployed to Windows Mobile 6.0 and 6.1 devices. Terrence Barr has created a screencast with detailed instructions that show developers how to get started.

Question 3: How can I learn about all the new features in JavaFX 1.2?

Answer: You can learn about all the new features in JavaFX 1.2 in an Features and Enhancements article written by Inyoung Cho. Additionally, it’s always good to have the JavaFX APIs handy whenever you learn how to use a particular class.

Final Thoughts

The JavaFX 1.2 APIs include many new features that allow desktop, mobile, and web developers to create compelling, dynamic, and feature-rich applications. Check them out.

NFC is a radio-communication standard that enables wireless data transfer between two devices at a very short distance -- less than 10 centimeters. NFC devices include a certain class of radio-frequency identification (RFID) tags and contactless smart cards. NFC devices operate within the 13.56 MHz frequency range, and they support extremely low data rates -- a maximum of 0.42 Mb per second.

Compared to Bluetooth and Wi-Fi, NFC technology operates at drastically reduced transfer rates and only within a very small proximity. If that's the case, why use NFC technology? Three reasons:

  • Setup time. NFC devices communicate instantly -- in less than 100 milliseconds -- when placed within range.
  • Power consumption. NFC tags and cards do not consume power, so their lifespan can be unlimited.
  • Cost. NFC tags and cards are inexpensive to manufacture compared to other wireless technologies.

This article shows you how to get Bluetooth applications to completely bypass the device-discovery and service-searching processes simply by using Near-Field Communication (NFC) technology and JSR 257: Contactless Communication API.

Read the full article

Check out the MAC applet blog entry regarding the new security warning on Macs. It's directed to Mac users who access javafx.com pages with embedded applets and who now see this warning:

Access dialog box

To prevent the message from appearing, check Allow all applets from "javafx.com" access.

It happens because Apple has changed to a site/URL-based security model in one of its recent Java updates. In previous updates of Java for Mac OS X, unless the applet was cached a Trust dialog box appeared with different text and unrestricted access information in the fine print: This applet was signed by "JavaFX Runtime," but Java cannot verify the authenticity of the signature's certificate. Click Trust to run this applet and allow it unrestricted access to your computer.

For more technical information about Java for Mac OS X v10.5 Update 4, see the Apple support documentation.

This article demonstrates that Java ME developers have a wide array of choices -- in addition to the full-featured Java ME SDK (which replaces the well-known Wireless Toolkit) -- to create and test applications.

The Sun Java ME SDK 3.0, considered the de facto standard SDK when it comes to mobile application development, integrates the very popular Java Wireless Toolkit for CLDC and the Java Toolkit for CDC as a single product. It lets developers create Java ME applications for the following JVM platforms:

  • CLDC/MIDP: The common JVM configuration for hundreds of millions of mobile phones
  • CDC/FP/PBP/AGUI: The JVM configuration for high-end smart phones and other devices
  • CDC/FP/PBP/BD-J: The JVM configuration for Blu-ray Disc players

In addition to the Sun Java ME SDK 3.0, this article include details on the following offerings and then summarizes them in a handy comparison table:

  • NetBeans 6.5 IDE
  • MOTODEV Studio for Java ME
  • Nokia S60, S40, and NFC SDKs
  • BlackBerry JDE 4.7
  • Sony Ericsson SDK 2.5 for Java ME
  • LG SDK 1.2 for Java ME

The Java ME SDK Comparison Matrix table shows a list of all Java ME SDKs and tools that are evaluated in this article, with an entry for API support for each one. (Note: The NetBeans IDE supports multiple Java configurations, so its entries in this matrix apply to when it is configured with the Java ME SDK 3.0.)

Read the full article

By Bruce Hopkins

After reading both Part 1 and Part 2 of the “Working with Bluetooth and GPS” series of articles, you were given a clear explanation of the example code that shows you how to do the following:


    1. Use the JSR-82 Bluetooth API to access the data from a Bluetooth-enabled GPS receiver
    2. Parse the data streams in NMEA format and obtain the coordinates of your current location
    3. Formulate an HTTP request to access an external mapping service
    4. Use the JSR-172 XML Parsing and Web Services API to parse an XML result
    5. Make a request in order to display a map image

Therefore, the purpose of this tech tip is to provide answers to the questions that were submitted by the readers of both articles in the series.

Question 1: Hi Bruce, I have a problem when I start the Mpowerplayer tool with any MIDlet that uses Bluetooth and the JSR-82 API. When the application tries to execute my MIDet, it immediately displays a java.lang.NoClassDefFoundError: javax/bluetooth/DiscoveryListener. What could be the problem?

Answer 1: The MPowerplayer made a change on how it handles JSR-82 libraries between releases #1127 and #1185. Unfortunately, it not explicitly stated in the documentation, but you need to make two simple changes in order to run MIDlets that require the JSR-82 API:


    1. Place any JSR-82 implementation in the /mpp-sdk folder. I’ve tested with the following JSR-82 implementations: Avetana (requires a license) and BlueCove (free open-source alternative).
    2. Rename that file to be called bt.jar.

After you make those two changes, you will be able to run any application requires the JSR-82 APIs.

Question 2: Hi Bruce, this is a nice article. I would like to know how to get GPS data from a mobile phone that already has a GPS receiver built-in.

Answer 2: If your mobile phone is MSA-compliant and already has a GPS radio built-in, then you don’t need to use the JSR-82 API to connect to a remote GPS receiver. All you need to do is use the JSR-179 Location APIs in order to retrieve your location data from an embedded GPS receiver. If you’d like to get started with the JSR-179 API, then Qusay Mahmoud has written a great article, Java ME and Location-Based Services, on that topic.

Question 3: I have a Bluetooth-enabled GPS receiver: the Holux Slim 236. I also have a Bluetooth-enabled computer. Can I run this example with what I have?

Answer 3: Yes, you should have no problem running the example code using the tools that you have. If you plan to use the current version of Mpowerplayer, then be sure to follow the instructions in the answer to Q1 first.

Question 4: Hi Bruce, thanks for creating this meaningful guide for developers. Your original article shows developers how to use the Avetana Bluetooth JSR-82 implementation with the Mpowerplayer SDK. The problem, however is that Aventana implementation only provides a free 14-day trial, and afterwards requires a license fee. Is there any way to configure the Mpowerplayer with the BlueCove JSR-82 implementation which is open source?

Answer 4: Yes, please refer to the answer provided to Q1 listed above in order to find out how to use the BlueCove library with the MPowerplayer SDK.

Question 5: Hi, I am having problem with this example with WTK 2.5.2 and NetBeans IDE 6.1 which are both installed in my PC. When I run this application on my PC, I’m not able to get any data from the remote Bluetooth devices.

Answer 5: Actually, the whole point of Part 1 in the two-part series was to show developers how to debug and test their JSR-82 applications on their PCs using the Mpowerplayer. Neither the WTK, the NetBeans IDE, nor the Java ME SDK have the ability to leverage the Bluetooth hardware of your PC in order to discover or search for services on remote Bluetooth devices.

Question 6: I have a Bluetooth-enabled phone with a built-in GPS receiver. I want to send NMEA data from the phone to a Bluetooth-enabled PC. I have a desktop application (Streets & Trips) that can consume GPS data. Since my phone support GPS and Bluetooth, is there a Java ME application that will enable my mobile phone to do this?

Answer 6: I don’t know of any Java ME applications that do this, however this sounds like the basis for another article!

Final Thoughts

Thanks to all the readers who took the time to provide feedback to this article series! Your input, thoughts, questions, and ideas are always welcome and appreciated.

By Vikram Goyal

Developing location-aware applications seems like a lot of work, especially since getting started seems to be the hardest part. In this tech tip, I will show you how to get started using the Location API (JSR 179) to get over the initial hurdle, and build a small location-aware application that you can use to tag your favorite spots.

I have tested and verified that the MIDlet works on a Nokia N95 device. When testing this on your device, make sure that it supports the Location API (JSR 179).

There are three steps in this tech tip

  1. Find and initialize a location provider
  2. Listen and act on location updates given by this provider
  3. Store and list favorite spots
The following paragraphs elaborate on these steps. It may help to have the entire source code of this MIDlet available for review while following the code snippets in these steps.

Step 1: Find and initialize a location provider

The process of discovery of a suitable location provider is broken down into two further steps. First, you need to create a set of criteria for the location provider. Second, you need to create an instance of this provider using these criteria.

The Location API provides two classes for these two steps: Criteria and LocationProvider.

To create a valid criteria, you create an instance of this class, set various parameters of the criteria. The code below, taken from the source code, creates a criteria that is suitable for our purposes.


  // create a very basic criteria for the provider
  Criteria criteria = new Criteria();
  criteria.setHorizontalAccuracy(Criteria.NO_REQUIREMENT);
  criteria.setVerticalAccuracy(Criteria.NO_REQUIREMENT);
  criteria.setPreferredResponseTime(Criteria.NO_REQUIREMENT);
  criteria.setCostAllowed(false);

As you can see, this is a very relaxed criteria. There are no specific requirements for horizontal or vertical accuracy or for response times. The only restriction is that there should not be a cost involved in using the Location API (possibly linked to the network provider).

We should be allowed to proceed only if the Location API built into your device can provide a provider based on these criteria. We do so, by asking the LocationProvider class for a provider using these criteria as the guiding set.


  // get the provider based on this criteria
  LocationProvider provider = LocationProvider.getInstance(criteria);

  // provider found
  if (provider != null) {
    provider.setLocationListener(this, -1, 0, 0);
  } else {
    display.setCurrent(
      new Alert("Error!",
      "Phone does not support Location Provider with the given criteria",
      null, AlertType.ERROR));
  }

If a provider with the given criteria cannot be found, a message is given to the user, and the MIDlet cannot proceed. But if the device can provide a valid location provider, the MIDlet sets up a location listener to listen to all the updates given by the location provider. In this case, the listener is the MIDlet itself.

Step 2: Listen and act on location updates

In the previous step, the location listener is set to the MIDlet itself. This means that the MIDlet must implement two methods provided by the LocationListener class. These two methods are locationUpdated(LocationProvider lp, Location l) and providerStateChanged(LocationProvider lp, int newState). The code below shows the implementation of the locationUpdated method.


  // if valid location is found, update the coords and status
  if(location != null && location.isValid()) {
    QualifiedCoordinates coords = location.getQualifiedCoordinates();
    coordsDisplay.setText(
      truncate(coords.getLatitude()) + ", " +
      truncate(coords.getLongitude()));
    statusDisplay.setText("Available");
    currentLocation = location;
  } else {
    coordsDisplay.setText("--, --");
    statusDisplay.setText("Unavailable");
    currentLocation = null;
  }

Each time the location of the device is updated, the location provider sends out the new location using the Location parameter in the locationUpdated method. The new location's coordinates can be picked using the getQualifiedCoordinates method.

Of course, if the device is out of range of the GPS satellites, then the provider will not be able to get the correct coordinates and, therefore, the actual location will be either null or invalid. The method checks for this before updating the status and the current location of the device.

The providerStateChanged method accepts updates when the location provider goes in and out of range of the GPS satellites. However, I found that my implementation on the Nokia N95 did not reliably send out updates for the providerStateChanged method. I therefore used the locationUpdated method to find out the status of the provider, However, I have kept the code in the providerStateChanged in case it works on other devices.

NOTE

To be on the safe side, the code in the locationUpdated method (and the corresponding providerStateChanged method) should be in its own thread to make sure that it doesn't block the normal MIDlet thread.

Step 3: Store and list favorite spots

Once the current location using the latitude and longitude have been found, it is a simple method to store this location with a tag as your favorite spot. The Location API makes it ridiculously simple by providing the Landmark store. You can either create your own Landmark store, or use the default one.

The default Landmark store is shared by all the MIDlets within the device. You create a Landmark store by using the static method provided by the LandmarkStore class. By passing in null, as shown in the following code, you are asking for the default store from this instance.

  store = LandmarkStore.getInstance(null);

The Landmark store contains the details of a location using the Landmark class. As shown in the following code, you can create a landmark by giving it a name (provide by you as a name for your favorite spot), a description (this is empty in the code below), and of course, the all important coordinates. The last parameter that is accepted by this constructor is an AddressInfo object that can be used to store actual address information, if supported by the provider. In this case, I have kept these details as simple as possible.


    // create the landmark
    Landmark landmark =
      new Landmark(name, "", currentLocation.getQualifiedCoordinates(), null);

    // and save it
    try {
      store.addLandmark(landmark, null);

      display.setCurrent(
        new Alert("Message", "Done", null, AlertType.INFO), displayForm);

      return;

    } catch(Exception ex) {
      handleError(ex);
    }

Once you have created the landmark, you can store it in the store using the addLandmark method. The second parameter specifies a category for that landmark, but I have kept it simple by putting it in the default category.

The list of existing landmarks can be retrieved using the getLandmarks method. This returns an enumeration that can be iterated over to display to the user in a list. This is shown in the following code.


  Enumeration en = store.getLandmarks();
  while(en.hasMoreElements()) {
    Landmark landmark = (Landmark)en.nextElement();
    landmarkList.append(
      landmark.getName() +
      " - " +
      truncate(landmark.getQualifiedCoordinates().getLatitude()) + ", " +
      truncate(landmark.getQualifiedCoordinates().getLongitude()), null);

Resources

By Bruce Hopkins

Java technology is an integral part of the new high-definition video standard: the Blu-ray Disc standard. In the past year, Sun published a two-part series to lower the learning curve for Java developers who want to get started using the Blu-ray Disc for Java (BD-J) platform.

In Part 1: Creating Your First Application, I provided an introduction to the BD-J platform and provided information on the various APIs that are required by BD-J, including GEM/MHP (Globally Executable Multi Home Platform) and Java TV. In Part 2: Responding to User Input, I showed you how to use the Java ME SDK to create an application that can respond to the user via the remote.

Among the thousands of readers of this series, several readers submitted the following questions in the Comments section of the articles.

Question: Is it really a good idea to use org.havi and org.dvb classes? Will this work on all Blu-ray players?

Answer: Yes, it is perfectly fine to use any of the use org.havi and org.dvb classes that are a part of the BD-J specification. Specifically, those classes originate from the GEM/MHP layer of the BD-J software stack, and all Blu-ray players must support them. Please refer to Part 1, where I provide a complete list of all the Java packages that must be supported in all Blu-ray players on the market (including PC-based Blu-ray players).

Question: I have following the problem when I compile the source file:

Fatal Error: Unable to find package java.lang in classpath or bootclasspath
Details message: target="${javac.target}"
deprecation="${javac.deprecation}" optimize="${javac.optimize}"
debug="${javac.debug}"
srcdir="${buildsystem.baton}" destdir="${build.classes.dir}"
bootclasspath="${platform.bootclasspath}"
includes="${javac.includes}"
encoding="${javac.encoding}">

Answer: If you’re using the Java ME SDK 3.0 platform and you’re having a compilation error, then please refer to the instructions provided in Part 2: I list step-by-step instructions on how to set up the Java ME SDK 3.0 to compile BD-J applications. Note that the Java ME SDK 3.0 cannot compile BD-J applications in its default state after you install the SDK. It must be configured with the BD-J libraries to compile BD-J applications.

Final Thoughts

Thanks to all the readers who took the time to provide feedback to this article series! Your input, thoughts, questions, and ideas are always welcome and appreciated.
By Vikram Goyal

One of the first steps in implementing Bluetooth applications on Java ME devices is the discovery process. In a nutshell, the discovery process is the process by which Bluetooth-enabled devices find each other, and then handshake to find out the services that they can each support. The next step, invariably, is learning how to send data between these paired devices.

In this tech tip, I will show you how to create a MIDlet that will search for devices and services, and then will allow the user to send a simple note to one of the found devices. I have tested and verified that the MIDlet works on a Nokia N95 device, and that it connects to a computer running Windows Vista, with Bluetooth support enabled.

I have broken down the whole process into the following steps:

  1. Start the discovery process.
  2. Query the devices found in the discovery process for supported services.
  3. Initiate and process an OBEX data exchange using the supported service URL.
The following paragraphs elaborate on these steps. It may help to have the whole source code of this MIDlet available for review while following the code snippets in these steps. The source code is available as a zipped file under Resources.

Step 1: Start the discovery process

The discovery process is used to tell the local Bluetooth stack that it should look within the nearby vicinity for any Bluetooth devices that are available for pairing. In the case of the MIDlet, this stack will be the implementation provided by your device provider for JSR 82.

This process of discovery is initiated by the discovery agent present in the local device, as shown in the following code.


    // get the local discovery agent
    agent = LocalDevice.getLocalDevice().getDiscoveryAgent();

    // start the inquiry for general unlimited inquiry
    agent.startInquiry(DiscoveryAgent.GIAC, this);

Once the discovery agent has started the discovery process, it will call various callback methods on a class that implements the DiscoveryListener interface. In our case, this is our MIDlet class.

Specifically, four methods of this interface must be implemented, two of which are interest to us in the discovery phase: deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) and inquiryCompleted(int discType). These two methods handle the discovery of a device and completion of the discovery process, respectively. As shown in the following code from the MIDlet, we use these methods to append our UI with devices as they are discovered and when the process is completed.


  public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
    try {
      // add the devices using the friendly names
      listofDevices.append(btDevice.getFriendlyName(false), null);
      // add to the devices hashtable
      devices.put(new Long(listofDevices.size()), btDevice);
    } catch(Exception ex) { handleError(ex); }
  }

  public void inquiryCompleted(int discType) {
    // once the inquiry is completed, show the list of devices to the user
    if(listofDevices.size() == 0) {
      display.setCurrent(nothing, noteBox);
    } else {
      display.setCurrent(listofDevices);
    }
  }

Step 2: Start the service discovery on discovered devices

Since our aim in this tip is to allow data transfer from our MIDlet to a compatible device, we need to find services on the discovered devices that enable this goal. To do so, we need to specify the correct attributes and UUIDs in our service discovery process. The following code shows how to do so:


  agent.searchServices(
    null,
    new UUID[] {new UUID(0x1105L)}, // we want the OBEX PUSH Profile
    device,
    this);

As you may guess, the code uses the local agent that we had used earlier to search for devices. We are not after a particular set of attributes, so we pass null as the first parameter, but the UUID must be OBEX PUSH profile, as this is the most open way of transferring data.

We talked about the DiscoveryListener interface which has two other methods that can be used to employ discovered services. These two methods are servicesDiscovered(int transID, ServiceRecord[] servRecord) and serviceSearchCompleted(int transID, int respCode). As the names suggest, the first method is called each time a service is discovered, while the second method is called when the service process has completed.

Each time a service is discovered, we need to find out the connection URL for that particular service on the respective device. This connection URL will be used to make the OBEX connection for putting our data across, and consists of the Bluetooth hardware address of the device, among other things. In the code below, this connection URL is retrieved in the servicesDiscovered method:


String connURL = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);

With this connection URL, we can now move to the process of transferring our data across to the discovered device.

Step 3: Send data using OBEX PUT

In this MIDlet, we are going to allow the user to type some text as a note, and then send that across using the discovered device/service. To do so, we will need the connection URL we got in the previous step (and of course, the note data as a String).


    // open a client session
    ClientSession clientSession =
      (ClientSession) Connector.open(connURL);

    // connect using no headers
    clientSession.connect(null);

    if(rHeaders.getResponseCode() != ResponseCodes.OBEX_HTTP_OK) {
      // the connection could not be established
      handleError(
        new Exception("Remote client returned invalid response code: " +
          rHeaders.getResponseCode()));
      return;
    }

    // if we are here, then response code was ok

    // create a new set of headers
    HeaderSet headers = clientSession.createHeaderSet();
    headers.setHeader(
      HeaderSet.LENGTH,
      new Long(noteBox.getString().length()));
    headers.setHeader(HeaderSet.NAME, "myNote.txt");
    headers.setHeader(HeaderSet.TYPE, "text/plain");

    // create an operation using the headers we have just created
    Operation op = clientSession.put(headers);

    // on this operation, create the output stream
    OutputStream out = op.openOutputStream();

    // and send the note
    out.write(noteBox.getString().getBytes());

To send the data, a client session is opened and a connection established with empty headers. At this point, your target device will ask for confirmation of receipt of data from a new device. It may also ask you for a passkey if you have never paired the devices before.

Once the connection is established, some headers that explain the purpose of the data are created, and a new Operation created with these headers. The Operation is then used to send the data via the available OutputStream.

The received note will be available in the default Bluetooth exchange folder on the target device.

Resources

By Bruce Hopkins

Let's assume that you're in the middle of your development cycle, and you realize that your mobile application needs to perform some very important but non-GUI-related operations such as:

  • Discover a local Bluetooth device in the vicinity
  • Communicate with a SIP registrar or proxy
  • Determine your geo-location via a GPS device

So now what do you do? You want to write your killer-app using great declarative syntax of JavaFX, but you also realize that the Java standard specifications for Bluetooth wireless technology (JSR-82), SIP communication (JSR-180), and location-based application development (JSR-179) and are available as Java ME APIs.

Fortunately, the JavaFX runtime is completely dependent upon (and compatible with) the Java virtual machine (JVM). Simply stated, it means the following:

  • Your JavaFX Mobile application has no restrictions on calling any class bundled in the JAR or any JSR API library that's present on the handset.
  • Your JavaFX Desktop application will work seamlessly upon any deployment platform that has the current version of the JRE:
    • For Windows machines, this will be Java 6, update 11 (or later)
    • For Mac OS X machines, this will be Java 5, update 13 (or later)

Independent of the operating system, your JavaFX Desktop application will also be able to call any class that's bundled in the JAR package for your desktop application. Note: On the Windows desktop, JavaFX runs on Java 5 and it degrades gracefully (for example, the Drag2Install feature does not work) — that is, it does not break your application.

Read the full article, with source code.

January 21, 2009, Wednesday. Sun Microsystems campus, Santa Clara, Caifornia.

These are notes from the presentations I attended at the Java Mobile, Media & Embedded Developer Days (M3DD). For more details, please go to the M3DD website and view the specific presentation's slides.

Sun Microsystems Mobile and Embedded community manager Roger Brinkley and evangelist Terrence Barr briefly welcomed the group to the second developer days, sponsored by Sony Ericsson and Sun Microsystems, then launched into the packed agenda. While the numbers rose and fell during the day, there were some 100 participants at the conference and another 150 participating via the live stream.

Marketing VP Eric Klein and Engineering VP Jeet Kaul gave the keynote speech. Eric stressed that the 2009 keywords for Java are "open" and "expressive." Eric noted that customers today consume and create business and personal content 24x7, across the screens of their life (mobile, desktop, television).

Eric spent some minutes reviewing Sun's "open" history, including the open collaboration around Java for over 12 years, resulting in Java being completely open source. Today's focus is on using Java to create a rich, immersive, expressive platform, so that developers can solve complex customer problems, using multiple data sources. The 6.5 million Java developers worldwide can combine with the 8 million content authors/web developers to grow a vibrant mobile platform. Jeet talked about his focus on streamlining the designer-developer workflow, embracing the native tools used by the community.

Jeet and Eric spoke of two current initiatives to address fragmentation issues: Java ODP and JavaFX. Java On Device Portal (ODP) allows the use of mobile widgets across global mobile devices, while JavaFX is positioned as the unifying technology for rich internet applications (RIA), web, and Java development across all screens (desktop, mobile, television). Eric also talked about Project Hydrazine (aka rocket fuel), which is an initiative to develop internet and operator services.

Florian Tournier, Sun senior product line manager, presented an overview of the Java mobility roadmap. First, the numbers:


  • 2.6 billion Java phone base
  • 6 billion Java Cards deployed
  • 840 million Java-enabled desktops
  • 40 million+ Blu-ray and TV devices

Florian stressed Sun's continuing commitment to open source and standards. Open source is exemplified by the regular phoneME releases -- phoneME Feature being the open-source implementation based on CLDC and MIDP, while phoneME Advanced is an open-source implementation of CDC for consumer devices and advanced phones -- and the open-sourcing of the LWUIT interface. LightWeight User Interface Toolkit (LWUIT), a standalone library, creates rich UIs easily for Java apps, which runs on any CLDC 1.1/MIDP 2.0 device. Standards are demonstrated by the Mobile Service Architecture (MSA) platform for Java in wireless, industry initiatives against fragmentation, and popular development/testing tools.

For 2009, Florian foresees the return of the feature (as opposed to smart) phone, with increasingly expressive experiences. He sees more emphasis on the browser, so discussed JSR 290, the mobile browser APIs for Java ME, mobile web servers (such as the Sprint Titan architecture), and Java Card 3. Innovations in Java show up in MSA2/MIDP3 functionality, CDC on phone (Sprint Titan with OSGi), modularization (Java SE first, then Java ME), and testing and tools in the Java ME SDK, with CLDC/CDC and BD-J support.

Phil Bender of CableLabs was the speaker at the next talk I attended. tru2way is Java-based middleware that allows interactivity with the television set, without requiring cable-top boxes. OpenCable project is on java.net, and there will be a developers conference on February 10. CableLabs also has a Visiting Engineer program. Cognizant's visiting engineer did a TeenLocator app, ported from Cognizant's IMS app for mobile, that lets users find a family member's mobile phone and map its location with driving directions.

The new Java TV standard for digital TV in Brazil came next, by Sun's Michael Lagally and Jens Pätzold. Interactive TV (TV plus apps) lets you augment A/V with Java apps, which are synchronized to the A/V content. Brazil has the world's largest dual terrestrial-mobile TV deployment. It has the world's 4th largest TV network (around 80 million viewers a day), so the Brazilian goverment has a standards body (Sistema Brasileiro de Televisao Digital, or SBTVD), which requested Sun to create royalty-free DTV specification. People use television to connect to the internet in Brazil, so it is used for many things as eGovernment apps (such as to obtain a driver's license).

Several lightning talks followed, with each person having 7 minutes to introduce his or her material. Patrick Curran talked about the Java Community Process (JCP). and noted there are 26 active Java ME JSRs. Nokia's Jackson Feijo Filho gave usability testing tips for mobile developers, including a usability checklist. Gail Rahn Frederick talked about multi-modal search in On Device Portals, and Medio Systems' handset-resident mobile search-driven ODP application, requiring JSR 135. SunLabs' Eric Arseneau showed a video on First, which will tie into his Project Squawk presentation on January 22.

Next, Ken Gilmer of Bug Labs talked about mobile Java on the BUG programmable and modular open-source gadget platform, which lets you use electronic building blocks to build personalized hardware devices. The BUG device is a mobile Linux computer in a small metal rectangle, the size of an older clunky mobile phone, with several pluggable modules (e.g., camera, LCD, GPS, and the lovely Von Hippel breakout board). It contains an OSGi runtime on a CDC JVM (Concierge on phoneME) and has an SDK with a virual BUG emulator.

That's it for today's presentation notes. If you'd like to follow the rest of today's or tomorrow's sessions, you can stream the conference. If needed, find the instructions here.

By Vikram Goyal

Mobile Media API (MMAPI) is a protocol- and format-agnostic API for playing and manipulating multimedia content in mobile devices. It is a diverse API and handles several different types of media seamlessly, depending upon device capabilities. In this tech tip, you will learn how to mix and play multiple media content at the same time.

Understanding the issues of mixing in MMAPI

On the face of it, mixing sounds in a mobile applications is a desirable attribute to have, especially for multimedia-rich applications like games. MMAPI provides you the ability to mix different media, but there are pitfalls. The following sections describe some of these issues.

Device fragmentation

MMAPI implementations that return a value of true for supports.mixing system property should, in theory, be able to do the following.

  • Support the playing of at least two tones simultaneously,
  • Use Manager.playTone() when another player instance is playing back audio, and
  • Support the playback of at least two instances of audio players.

In practice, not all MMAPI implementations follow these guidelines. This is due to device fragmentation. You should consult the design guidelines supplied by the device manufacturer to find out the capabilities of the device that you are working with.

Multiple player instances

With multiple player instances active in an application, there is a danger of too many resources being taken up to service these instances. When a player instance is in a prefetched/realized state, it will become a memory liability if kept around for a long time, especially because player instances in this state can request exclusive access to system resources, like the audio hardware. Thus, even if your device's MMAPI implementation allows for more than 2 player instances to be active at any time, it is prudent to keep this number low.

MIDI, tones, and sampled audio

As I said earlier, what can be mixed depends on your device's MMAPI implementation. Generally, most implementations will allow you to mix one instance of sampled audio and one instance of either a simple tone or MIDI sound, or both.

Putting together the code

Mixing sounds is a common feature in games where a background sound plays throughout the game, while various user or application events generate their own short lived sounds. In the following example, I will use a basic sampled audio as a background score, while various events during the game play will be mixed using MIDI and Tone control. The example is created and run using Netbeans 6.5. Make sure that MMAPI is selected as an optional API while creating this application, as MIDIControl is not part of the basic MIDP 2.0 MMAPI package.

When you run this code (supplied as a Netbeans project), you will be able to mix a MIDI sound and a system-generated tone with the continuous background music. This is tested in Sun Wireless Toolkit 2.2 supplied with Netbeans. If you run this in other toolkits, or better still, on an actual device, you will need to make sure that MIDIControl is supported.

Resources


EXAMPLE SOURCE CODE

/*
 * TechnicalTipMIDlet.java
 *
 */

import javax.microedition.media.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.media.control.MIDIControl;

/*
 * TechnicalTipMIDlet mixes audio, MIDI and tone
 * @author  Vikram Goyal
 */
public class TechnicalTipMIDlet extends MIDlet implements CommandListener {

  // define variables

  // the players for background music and MIDI
  private Player backgroundMusic = null;
  private Player aPlayer = null;

  // the MIDIControl extracted from aPlayer
  private MIDIControl mControl = null;

  // display items, the display
  private Display display = null;

  // and an alert
  private Alert alert = null;

  // commands to exit, for aCommand (MIDI) and bCommand (tone)
  private Command exitCommand = null;
  private Command aCommand = null;
  private Command bCommand = null;

  public TechnicalTipMIDlet() {

    // initialize the display
    display = Display.getDisplay(this);

    // a message for the user
    alert = new Alert("Message");
    alert.setString("Press A to play a tone, Press B to play a MIDI");
    alert.setTimeout(Alert.FOREVER);

    // create commands
    exitCommand = new Command("Exit", Command.EXIT, 1);
    aCommand = new Command("A", Command.ITEM, 1);
    bCommand = new Command("B", Command.ITEM, 1);

    // add to alert
    alert.addCommand(exitCommand);
    alert.addCommand(aCommand);
    alert.addCommand(bCommand);

    // set this class as command listener
    alert.setCommandListener(this);

    // and initialize the player instances
    initialize();
  }

  private void initialize() {

    // create and prefetch player instances
    try {

      // for the background music, load a simple wav file and put it on
      // infinite loop
      backgroundMusic =
        Manager.createPlayer(
          getClass().getResourceAsStream("music.wav"), "audio/x-wav");
      backgroundMusic.prefetch();
      backgroundMusic.setLoopCount(-1);

      // create the MIDI player, prefetch
      aPlayer = Manager.createPlayer(Manager.MIDI_DEVICE_LOCATOR);
      aPlayer.prefetch();

      // and extract the MIDIControl
      mControl =
        (MIDIControl)aPlayer.getControl(
          "javax.microedition.media.control.MIDIControl");

    } catch(Exception ex) {
      handleError(ex);
    }
  }

  public void commandAction(Command cmd, Displayable disp) {

    // handle the exit command
    if(cmd == exitCommand) {
      destroyApp(true);
      notifyDestroyed();
      return;
    }

    try {

      // if it's the aCommand
      if(cmd == aCommand) {

        // play a short MIDI event
        mControl.shortMidiEvent(MIDIControl.NOTE_ON | 11, 60, 100);
      }

      if(cmd == bCommand) {

        // if bCommand, use the Manager class to play a simple tone
        Manager.playTone(61, 1000, 100);
      }
    } catch(Exception ex) {
      handleError(ex);
    }
  }

  public void startApp() {

    try {

      // start the background music if it was created successfully
      if(backgroundMusic != null) backgroundMusic.start();
      else handleError(new Exception("Error with background player"));
    } catch(Exception ex) { handleError(ex); }

    display.setCurrent(alert);
  }

  public void pauseApp() {
  }

  public void destroyApp(boolean unconditional) {

    try {

      // close players
      if(backgroundMusic != null) {
        backgroundMusic.close();
        backgroundMusic = null;
      }

      if(aPlayer != null) {
        aPlayer.close();
        aPlayer = null;
      }

    } catch(Exception e) {
      handleError(e);
    }

  }

  // handles errors
  private void handleError(Exception ex) {
    alert.setTitle("Error");
    alert.setString(ex.getMessage());
    display.setCurrent(alert);
    ex.printStackTrace();
  }
}

Vikram Goyal is the author of Pro Java ME MMAPI, published by Apress. This book explains how to add audio, video and other multimedia capabilities to a Java-enabled phone. Vikram is also the author of the Jakarta Commons Online Bookshelf and helps manage a free craft projects website.

Bruce Hopkins serves up Part 2 of his series on Blu-ray Disc Java development.

Part 1 introduces the BD-J platform and discusses the significant differences between the system requirements for developing, compared to playing, Blu-ray content. Additionally, we learn that the BD-J platform comprises various other supporting APIs, including GEM/MHP (Globally Executable Multi Home Platform) and Java TV. We are introduced to the application lifecycle of BD-J Xlets.

In Part 2, Hopkins delves into the Java ME SDK 3.0, which is the perfect tool for all Java ME development — whether you're doing Blu-ray application development or mobile phone application development. The Java ME SDK 3.0 provides substantial enhancements to its predecessor, the Wireless Toolkit for CLDC 2.5, mainly due to the fact that it allows developers the ability to author, edit, and compile all Java ME applications — especially of course, BD-J applications. Using the BD-J APIs, developers can create Java ME applications for all Blu-ray disc players, including the Sony PlayStation 3 gaming console.

Read the full article

A Java mobile widget is a small chunk of Java ME code installed and operated by the Java On Device Portal (Java ODP) technology.

While other Java ODP solutions force developers to write mobile widgets using a proprietary scripting language, the Java ODP platform leverages Java ME technology. You can write widgets in pure Java and take advantage of Java's full capabilities, such as packages for Personal Information Management (PIM), location-based services (LBS), multimedia, and more.

Register here to join program to receive access to the Early Access SDK.

By Thomas Ng

While developing your JavaFX applet or application by using NetBeans IDE 6.5 for the JavaFX 1.0 platform, you might want to run the JavaFX application/applet offline for debugging and testing purposes. Following are the steps to run the JavaFX application or applet when your machine is disconnected from the network.

Requirements:

You must have Java SE Development Kit (JDK) 6 Update 10 (or later) installed on your local machine.

Your applet or application must be JNLP enabled.

1. Download the following files to your local machine:

    http://java.com/js/deployJava.js
    http://dl.javafx.com/dtfx.js
    http://dl.javafx.com/javafx-loading-100x100.gif
    http://dl.javafx.com/javafx-loading-25x25.gif

2. Save the files to a local directory on your machine. For example:

    c:\offline\deployJava.js
    c:\offline\dtfx.js
    c:\offline\javafx-loading-100x100.gif
    c:\oflline\javafx-loading-25x25.gif

3. Edit the dtfx.js file:

    a. Replace the reference to http://java.com/js/deployJava.js with file:/c:/offline/deployJava.js.
    b. Replace the reference to http://dl.javafx.com/javafx-loading-100x100.gif with file:/c:/offline/javafx-loading-100x100.gif.
    c. Replace the reference to http://dl.javafx.com/javafx-loading-25x25.gif with file:/c:/offline/javafx-loading-25x25.gif.

4. While your machine is connected to the network, run the following command, which ensures that the latest JavaFX runtime is installed into your local cache:

    javaws -import http://dl.javafx.com/javafx-cache.jnlp
    This command ensures the latest JavaFX runtime is cached in your system. You will see a Java splash screen, followed by a progress dialog box, if any download takes place. After that, the command will exit silently, which means you now have the latest JavaFX runtime cached. If an error is encountered, an error dialog box appears.

5. Disconnect your machine from the network.

6. Ensure that the JNLP file for your JavaFX applet or application uses the following <extension> tag for its JavaFX runtime:

    <extension name="JavaFX Runtime" href="http://dl.javafx.com/javafx-rt.jnlp"/>
    This is the default that is generated by the NetBeans IDE. This allows your application/applet to be launched offline by using the cached JavaFX runtime.

7. In your applet or application HTML page, change the reference of dtfx.js to your local copy.

    a. For example, find this reference: <script src="http://dl.javafx.com/dtfx.js"></script>
    b. Change it to the following: <script src="file:/c:/offline/dtfx.js"></script>

8. Run your application or applet offline.

The compile and run functions of the NetBeans IDE always regenerate the HTML and JNLP files of your JavaFX applet or application and overwrite the changes you made to default value of http://dl.javafx.com instead of to your local copy. Therefore, you must make a copy of these offline-specific HTML and JNLP files and navigate to them directly when running offline. Remember to change the JNLP href in each offline JNLP file that points to the offline copy.

You can continue to work on your JavaFX applets and applications while your computer is offline.


Thomas Ng is a software engineer in the Java Deployment team at Sun Microsystems. He has worked on developing Java Web Start software since version 1.0.

This article is by J.D. Moore (User Experience manager, Emerging Market Services, Nokia) and Daniel Orwa Ochieng (lecturer at the School of Computing and Informatics at the University of Nairobi's College of Biological and Physical Sciences, Kenya).

Mobile user-interface heuristics have shown these factors as critical in ease-of-use:


  • Be consistent and build on experiences found locally in the user's environment
  • Offer efficient menus, avoiding deep hierarchies -- particularly critical where there is rampant illiteracy.
  • Provide clear feedback in the local language, for optimum comprehension.
  • Let the user be in control, including decisions on resource usage (cost control).
  • Simplify dialog boxes and navigation, and expect to deal with diversity via a simple user interface.
  • Offer useful text labels with localized iconography (culturally sensitive).

As an example of these theories in action, Gergely Herenyi of Nokia developed an FM Radio Reference MIDlet, posted on the Nokia Forum. The MIDlet supports user-generated localization for an application to connect people to community radio stations. You can download the full source code from that site as well.

Read the full article

By Bruce Hopkins

As you may recall from Part 1 of this series, I showed you two example applications that used the Session Initiation Protocol (SIP) to send a simple message asynchronously from one application to the other. In this tech tip, we are going to explore why the REGISTER method type is important and learn how to use it.

The SIP protocol supports the following method types when SIP devices are communicating:

ACKMESSAGEREFER
BYENOTIFYREGISTER
CANCELOPTIONSSUBSCRIBE
INFOPRACKUPDATE
INVITEPUBLISH

In the previous example, you saw how easy it was for each user to communicate with each other using the MESSAGE method type. This was, of course, due to the fact that each user had a routable IP address, and there were no barriers in place (such as a firewall) to impede the communication between the devices. This gets a little tricky, however, when one or both of the users are located behind a firewall or NAT proxy as shown in Figure 1.

Incoming-Outgoing SIP Traffic

Figure 1. Incoming Requests to Devices Behind a Firewall Are Blocked

If you're lucky, you can always ask the network administrator at your organization to open a port on the firewall for your device. However, that solution is definitely not scalable -- what if other people in your company wanted a port open for their devices, too? Additionally, what would you need to do if the IP address of your mobile device changed? Your network administrator would have to reconfigure the firewall to point to your new address. Figure 2, below, shows the scalability problem if you open a port on the firewall for each SIP device.

Incoming SIP

Figure 2: Opening Individual Ports on the Firewall for Incoming SIP Requests Is Not a Scalable Solution

Obviously, there must be a scalable solution for multiple SIP devices to communicate if one or more of them are located behind a firewall. Fortunately, that's where the REGISTER method type comes into play. As you can see in Figures 3 and 4 below, the use of a SIP proxy and the REGISTER method type provide a simple, yet scalable solution. When a SIP device is behind a firewall, it needs to send a REGISTER method type to the external SIP proxy located outside the firewall. For the purposes of this tech tip, the external SIP proxy will also act as a registrar.

SIP Proxy

Figure 3. REGISTER Requests are Sent Directly to External SIP Proxy

Incoming SIP Routing

Figure 4. Incoming SIP Messages Are Now Routed to the Proper Devices

What happens when your SIP device get a new IP address? All it needs to do is send a new RIGISTER request to the SIP proxy with its new IP address – and that’s it! The SIP Proxy will route all messages to your device now that it knows how to contact you.

If you want to try this out yourself, all you need to do is to standup the embedded SIP Proxy/Registrar inside the Sun Java Wireless Toolkit 2.5.2 application. To start the SIP proxy, execute the “Utilities” application with the Wireless Toolkit program group. After the Utilities application starts, click on the “Start SIP Server” option. After the server starts, you can then now register yourself with the SIP Proxy by sending to it a REGISTER message. The code in Listing 1 provides a practical example on how it is done:

    public void register(final SipClientConnectionListener listener, final Thread waitFor){
        Thread t = new Thread() {
                public void run() {
                    runGauge();

                    try {
                        try {
                            if (waitFor != null) {
                                waitFor.join();
                            } else {
                            }
                        } catch (InterruptedException ie) {
                        }

                        scc = (SipClientConnection)Connector.open("sip:" + proxyAddress +
                                ":5060;transport=udp");
                        scc.setListener(listener);
                        scc.initRequest("REGISTER", scn);

                        String adr =
                            myDisplayName + " ";
                        scc.setHeader("To", adr);
                        scc.setHeader("From", adr);
                        scc.setHeader("Content-Length", "0");
                        scc.setHeader("Max-Forwards", "6");
                        uaStatus.setStatus(REGISTERING);
                        scc.send();
                        uaStatus.waitUntilChanged();
                        progressGaugeFinished = true;
                    } catch (Exception e) {
                        e.printStackTrace();
                        failMessage = e.getMessage();
                        commandAction(failedCmd, currentDisplay);

                        return;
                    }
                }
            };

        t.start();
    }

Listing 1. Using the JSR-180 API to Create and Send a Register Request

The following image shows the results of the REGISTER request that was sent to my SIP Proxy. As you can see, I am now registered with the proxy. Now anyone can send a message to me via the proxy. Be sure to note that the proxy also functions a handy debug tool, and it shows you the contents of the SIP messages that it proxies.

REGISTER Request

Figure 5. The Result of the REGISTER Request Sent to the SIP Proxy

Conclusion

It doesn’t take a lot of effort to use the JSR-180 API to register your device with a SIP Proxy/Registrar. If you’re looking for a fully functioning example, be sure to try out the GoSIP demo application in the Sun Java Wireless Toolkit 2.5.2*. This application works out-of-the-box with the embedded SIP Proxy in the Wireless Toolkit, so that you can register multiple devices and to communicate via the proxy.

*NOTE: The Sun Wireless Toolkit is called the Java ME SDK as of version 3.0.

By Bruce Hopkins

This article shows how easy it is to use the JSR-82 (Bluetooth) API to access the data from a Bluetooth-enabled GPS receiver, parse the data streams, and obtain the coordinates of current location. Additionally, you'll see how to formulate the HTTP request to access an external mapping service, use JSR-172 (XML Parsing and Web Services) API to parse the result, and make the final request to obtain the map image. Both JSR-82 and JSR-172 are included in the Java ME MSA standard.

Read the full article.

Also, see the Follow Up to this series, where Bruce Hopkins answers questions from readers of this series.

By Bruce Hopkins

The Java platform for Blue-ray disc players is called BD-J. In the first part of this series, I'm going to cover the following topics:

* Basic Requirements for BD-J Development
* What the BD-J Platform Can Do
* BD-J Specification and APIs
* Understanding the Blu-ray Profiles
* Xlets and Xlet Lifecycles
* Creating Your First BD-J Application

Included is sample code that creates a simple application that implements all the Xlet lifecycle methods. It performs a very simple operation: writing text on the screen.

I'm going to assume that you have absolutely no Java ME or video-content creation experience whatsoever. Having that said, let's get started.

Continue on to the full article

In mobile applications, developers typically rely on home-grown data-interchange formats or on the Extensible Markup Language (XML). The advantage of the former is that it can be tailored to particular situations for the purpose of maximizing performance and/or computational resources. The advantage of the latter, when used over HTTP, is that it is a de facto standard for data interchange. In addition, the text-based/human-readable representation used in XML makes it easier to debug.

Yet these two approaches also have disadvantages, one being proprietary in nature, non-standard, and potentially non-interoperable, while the other one could be considered too heavy and verbose for data representation, again this is especially true for mobile and embedded applications.

An alternative to consider is JSON, a lightweight data-interchange format. JSON is defined as part of JavaScript (ECMAScript) scripting language. Being native to JavaScript, JSON is ideal for browser-based applications. But JSON is not limited to JavaScript, and its lightweight characteristics make it very attractive for mobile and embedded applications in general.

This article covers the following topics:

- JSON-Supported Data Types
- JSON on Java ME
- Using JSON
- The Core JSON JSONObject Class
- The Example DataTypes Class
- Serializing to JSON: Generating JSON Text
- Deserializing JSON: Initializing the Class from JSON Text
- Using the Serialization Methods

Read the full article

During the week of August 18, 2008, we encouraged you to "Ask the Experts" your questions about the recent JavaFX Preview SDK release. In this session, our experts were Joshua Marinacci, Martin Brehovsky, and Lawrence McDonough of the JavaFX engineering team. Jeff Dinkins, engineering manager for Java Graphics & Media, also pitched in for one question.

You can read a transcript of the session. The following topics are addressed:

• Using a node-based approach versus Swing component-based approach
• Putting a layout component in a Frame object or a layout component
• Getting different results when invoking static methods on a class
• Deploying applets
• Decreasing the Java installation time and size
• Comparing Java Server Faces (JSF) and JavaFX
• Working with Hibernate and Seam
• Adding more components
• Developing a web-mapping/tile-based server solution in JavaFX versus JavaScript
• Working with the previous release's Eclipse plugin
• Supporting the designer-developer workflow
• Using multiple inheritance versus interfaces
• Improving the sample applications
• Communicating with applets dragged outside the browser
• Using data binding with Java objects
• Using traditional web technologies for javafx.com site
• Installing JavaFX
• Open-sourcing the JavaFX platform
• Supporting javafx.ext.swing classes and multiline formatted text
• Developing third-party components
• Providing database-driven samples
• Providing local persistence storage (or embedded database)
• Building graphic assets for use in JavaFX
• Using the Scene Graph UI
• Persisting UI state and user data
• Using transparent backgrounds
• Needing more JavaFX documentation
• Defining the tween keyword
• Encoding/decoding video formats and audio types

JavaFX expert Jim Weaver continues his series of articles with this latest one, TableNode: Creating a Custom Scrollable Table in JavaFX.

In this collaborative series, he works with graphics designer Mark Dingman of Malden Labs on an imaginary Sound Beans application. The objectives are to show how to create custom UI controls in JavaFX, and to provide a case study in how a graphics designer and an application developer can work together effectively in developing JavaFX applications. Each
article contains the source code and Java Web Start to run the application.

Read the article series in his JavaFXpert.com blog.

The JavaFX family of products includes the tools and platform SDK that developers, web scripters, and designers need to create dynamic applications for the next generation of web-delivered content. Sun recently released a JavaFX Preview designed to help early adopters become familiar with JavaFX.

If you have a question about the JavaFX Preview, post your questions during this session and get answers from three key members of Sun's JavaFX engineering team: Josh Marinacci, Martin Brehovsky, and Larry McDonough.

Typically, a one week period is designated for questions on a specific Ask the Experts topic. You can submit a question on that topic any time during that week. We'll collect the questions periodically and send them to the experts. We'll then post a selected set of questions and answers. Although the experts will try to answer as many questions as feasible, there is no guarantee that all questions will be answered.

Get more information at the Ask The Experts website.

In August and September 2007, the Sun Developer Network staff started a Learning Curve Journal, a series designed to help users get started with the JavaFX Script programming language (shortened to JavaFX Script hereafter). A number of significant advances have been made to the language since then. Perhaps most important is the availability of a compiler-based version of JavaFX Script, which replaces the earlier interpreter-based version of the language. The Learning Curve Journal described the use of the interpreter-based version of the language. The Learning Curve Journal has been updated to show you how to use the compiler-based version of the language. Other changes have been made to make the articles current.

Part 1: Exploring JavaFX Script gets you started with a simple JavaFX program, that is, a simple program written in the JavaFX Script language. You'll learn how to set up your environment for programming in JavaFX Script and how to build and run a JavaFX program.

Part 2: Declarative User Interfaces focuses on the declarative style of coding enabled by JavaFX Script. You'll see how this style can make the code for a graphical application simpler and more intuitive.

Part 3: JavaFX Script Functions shows you how to use JavaFX Script functions to implement actions in a Java FX program.

For some developers, working with wireless technologies can be daunting -- and sometimes downright intimidating. When communication is wireless, you can't just "look up" and see, for instance, 1 MB of data going by. In addition, it is really difficult to debug wireless applications once they are deployed to a mobile device, since you don't have access to system traces or log files to pinpoint the errors while the application is running.

This technical article addresses the following tasks:

* Helps demystify some wireless concepts using Bluetooth and the JSR-82 API
* Shows how to run and debug Java ME Bluetooth applications on your desktop computer
* Explains how to read data from a Bluetooth-enabled GPS device

The good news is that you're going to learn how to construct a low-cost solution that allows you to install, debug, and test your JSR-82 applications on your computer. I'm going to introduce to you the Mpowerplayer, a CLDC emulator for the computer that can be configured to behave like a JSR-82 Bluetooth-enabled phone. With this configuration, the Mpowerplayer will behave just like a JSR-82 Bluetooth-enabled mobile phone, but you'll have access to the System.out and have the ability to view stacktraces, both of which are essential in debugging your wireless application.

Read the full article and download the source code.

Also, see the Follow Up to this series, where Bruce Hopkins answers questions from readers of this series.

Sun Microsystems and DigiSoft.tv have each explored using Java technology to address the challenges related to content development for the IP-based interactive TV market. Developers face tough challenges writing and deploying applications for existing proprietary middleware platforms.

To address these developer challenges, Sun and DigiSoft worked together and, in April 2008, announced the general availability of a Java Platform, Micro Edition (Java ME) based client platform for IPTV set-top boxes (STBs). This client solution incorporates Sun's Java technology-based media client and Digisoft.tv's middleware/SDK. This combined solution is suitable for IP-based media receivers.

Sun's Sr. Product Line Manager for digital media, Jennifer Yonemitsu, recently sat down with Digisoft.tv CEO John Allen to discuss this joint solution.

Read the full interview.

By C. Enrique Ortiz

Near-field Communication (NFC) is characterized as a very short-range radio communication technology with a lot of potential, especially when applied to mobile handsets. Imagine yourself using your cellphone to interact with posters, magazines, and even with products while at the store, and with such interaction initiating a request or search for related information in real-time. Other usages of NFC include the electronic wallet to make payments using your handset, the same way you do with your credit card. With NFC all this is possible. But NFC is still a young technology. That said, NFC-enabled handsets are being introduced into the market, and deployments and pilots around the world are occurring. This article explores NFC and how you can leverage it in your Java application by using the Contactless Communications API. Read the full article.

By Richard Marejka

Question: How do you programmatically detect the presence of the JSR 82 Bluetooth APIs?

Answer: It would be nice if the answer were this:

import	javax.microedition.*;
import	javax.bluetooth.*;

...

String	BluetoothVersion = System.getProperty( "bluetooth.api.version" );
boolean	isBluetoothHere  = false;

...

if ( BluetoothVersion != null )
	isBluetoothHere = true;

On a Bluetooth v1.0 device, the previous code will always result in:

BluetoothVersion = null;
isBluetoothHere  = false;

that is, a negative or a false negative detection of Bluetooth.

The reason it is not as simple as the first code sample lies in the first version of JSR 82 Bluetooth APIs. In the original Bluetooth specification, JSR 82 v1.0a (Apr 5, 2002), section 3.3.4 Device Properties states: "This API defines the additional system properties that may be retrieved by a call to LocalDevice.getProperty(), as shown in Table 3-2."

The table in question contains a bluetooth.api.version property that will return 1.0 if Bluetooth is supported. To correctly discover Bluetooth on a v1.0 device, the required code follows:

import	javax.bluetooth.*;

...

String	BluetoothVersion = null;
boolean	isBluetoothHere  = true;

...

try {
	Class.forName( "javax.bluetooth.LocalDevice" );    // does the class exist?

	BluetoothVersion = javax.bluetooth.LocalDevice.getProperty( "bluetooth.api.version" );

} catch( ClassNotFoundException cnf ) {    // class does not exist -> no Bluetooth
	isBluetoothHere  = false;
}

Access to javax.bluetooth.LocalDevice is required to determine if Bluetooth is present. The Class.forName() method is used to test for the presence of a class in the run-time environment. If the class is found, then LocalDevice can be safely accessed to retrieve the Bluetooth version.

This somewhat non-intuitive detection method was changed in JSR 82 v1.1 (Sep 02, 2006, Maintenance Release 2). Section 3.3.4 has been revised to include the sentence: "Additionally, all properties defined in the Bluetooth API and available through the LocalDevice.getProperty method MUST also be available through the CLDC System.getProperty() method."

The same section also defines the property/value pairs in Table 3-2:

bluetooth.api.version  "1.1"
obex.api.version       "1.1"

which means the System.getProperty() method will work as expected.

As for JSR 248 MSA: Bluetooth is conditionally mandatory; that is, if there is Bluetooth hardware then the JSR 82 APIs are present. Bluetooth v1.1 is part of both MSA and MSA Subset.

Lastly, note that the first code sample will still work and produce the correct answer on both Bluetooth 1.0 and 1.1 devices. In cases where there is no Bluetooth, the result is:

isBluetoothHere  = false;
BluetoothVersion = null;

or if Bluetooth is present, the result is either

isBluetoothHere  = true;
BluetoothVersion = "1.0";

or

isBluetoothHere  = true;
BluetoothVersion = "1.1";