Would you like to tell us how we are doing?

You bet No thanks

Sorry about the red box, but we really need you to update your browser. Read this excellent article if you're wondering why we are no longer supporting this browser version. Go to Browse Happy for browser suggestions and how to update.

Communication API

The Communication API simplifies the process of interacting with web services and other apps. The objects that you create using this API automate the process of finding an available network transport, creating a thread-safe connection, and negotiating an exchange of data with the URI or URL end point that you specify. The API is implemented in the net.rim.device.api.io.messaging package.

Within the Communication API, URI and URL end points are called destinations. You can use objects that implement the SenderDestination interface to send data to a web service and access the response. Similarly, you can use objects that implement the ReceiverDestination interface to subscribe to a push service and provide access to new messages from that service. Use the DestinationFactory class to create an object that implements the Destination subinterfaces that suits your requirements.

Interface

Description

BlockingSenderDestination

You can use this interface to send a message to a web service, but this object blocks thread execution while it waits for a response from the web service.

Alternatively, BlockingSenderDestination can return a MessageFuture object. This allows thread execution to continue until you invoke one of the get() methods from the MessageFuture.

When you invoke sendReceive() in BlockingSenderDestination to send a message and wait for a response, you should not invoke it from the main event thread.

NonBlockingSenderDestination

You can use this interface to send a message to a web service. In the parameter list, pass your implementation of the MessageListener interface to receive the response from the web service.

BlockingReceiverDestination

You can use this interface to subscribe to a push service and block thread execution until you receive confirmation of your subscription request.

NonBlockingReceiverDestination

You can use this interface to subscribe to a push service. In the parameter list, pass your implementation of MessageListener to receive push messages.

FireAndForgetDestination

You can use this interface to send data to a web service when you don't expect a response.

Data that you send to and receive from a web service is wrapped in a Message object. You can set the headers and content of the data that is sent to a web service in the Message object. Alternatively, you can allow the Communication API to choose reasonable default values for your request. For example, you can request a web page by invoking SenderDestination.send() without specifying an HTTP GET command.

You can also instruct the API to automatically parse the response data from a web service. If you implement the MessageProcessor interface with your parser class, you can supply your parser object to the method in DestinationFactory that creates your Destination object. You can then retrieve the parsed response using Message.getObjectPayload().

The net.rim.device.api.io.parser packages contain message processors for a variety of standard data formats that are used on the Internet. The packages include parsers for:
  • JSON
  • RSS (RDF, Atom)
  • SOAP
  • XML

To improve efficiency, the Communication API provides large responses from web services in an InputStream object. An app can request additional data as required rather than downloading a large amount of data at once and storing it in memory on the smartphone. This approach enables you to make better use of both network bandwidth and memory.

Communicating with HTTP servers

To send a command to an HTTP server, you need a SenderDestination object to communicate with an end point. The SenderDestination object is responsible for queuing and retrieving messages for delivery. The DestinationFactory class creates and maintains a list of Destination objects that you can use to communicate with an end point.

Before you create a SenderDestination, you should check whether one exists by invoking getSenderDestination(). You can access an existing destination by providing the name of the Context object that you supplied when you invoked any of the DestinationFactory.create...() methods.

When you finish exchanging data with an end point, you should invoke DestinationFactory.release() or DestinationFactory.destory(). The release() method removes the association between a Destination and the inbound and outbound message queues. After you invoke release(), the API continues to attempt the delivery of messages in the queue. You can use release() when your app is not in a state to send and receive messages. In addition to removing the association between a Destination and the a message queue, destroy() also destroys the message queue. After you invoke destory(), any messages in the queue will be deleted.

A message contains the details of your command, including the HTTP request method and any additional data that you require. If you do not specify all parameters for your message, default values are provided by the Communication API.

After you send your message, you may need to listen for a response. For BlockingSenderDestination objects, you need to create a Thread object when you invoke one of the sendReceive() methods. For NonBlockingSenderDestination objects, you must create a MessageListener object to receive the response.

In either case, you need to process a Message object that contains the response. By default, the body of the Message contains the raw response data. You can choose to specify a message processor from the net.rim.device.api.io.parser package, or create your own using the MessageProcessor interface.

If necessary, you can connect multiple message processors together. The MessageProcessorChain class shares memory between the MessageProcessor objects to improve efficiency. For example, if you receive video data that uses custom encoding and compression, you can separate the decoding and decompression logic into separate message processors, and then use MessageProcessorChain to group them together.

Request data using a BlockingSenderDestination object

import net.rim.device.api.io.messaging.*;
import net.rim.device.api.io.URI;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import java.io.*;

public class NetworkSample extends UiApplication 
{
    public static void main(String[] args) 
    {
        NetworkSample app = new NetworkSample();
        app.enterEventDispatcher();
    }
    public NetworkSample() 
    {
        pushScreen(new BlockingSenderSample());
    }
}

class BlockingSenderSample extends MainScreen implements FieldChangeListener
{

    ButtonField _btnBlock = new ButtonField(Field.FIELD_HCENTER);

    private static UiApplication _app = UiApplication.getUiApplication();

    private String _result;

    public BlockingSenderSample()
    {
        _btnBlock.setChangeListener(this);
        _btnBlock.setLabel("Fetch page");

        add(_btnBlock);
    }

    public void fieldChanged(Field button, int unused)
    {

        if(button == _btnBlock)
        {

//Create a thread from which to call BlockingSenderDestination.sendReceive().
            Thread t = new Thread(new Runnable() 
            {
                public void run()
                {

//Create a Message object to hold the response from the URL.
                    Message response = null;

//Create a URI object to pass to the DestinationFactory class.
																				String uriStr = "http://www.blackberry.com";

//Create a BlockingSenderDestination object.
                    BlockingSenderDestination bsd = null;

//Retrieve the BlockingSenderDestination object for your context, if one exists. 
                    try
                    {
                        bsd = (BlockingSenderDestination)
                                   DestinationFactory.getSenderDestination
                                       ("CommAPISample", URI.create(uriStr));

//If no BlockingSenderDestination exists, create one.
                        if(bsd == null)
                        {
                            bsd =
                              DestinationFactory.createBlockingSenderDestination
                                  (new Context("CommAPISample"),
                                   URI.create(uriStr)
                                   );
                        }

//Send a message and wait for the response.
                        response = bsd.sendReceive();

//If the web service sent a response, process the response.

                        if(response != null)
                        {
                            BSDResponse(response);
                        }
                    }

//Catch any errors that occur if the message could not be sent for some reason.
                    catch(Exception e)
                    {
                        // process the error
                    }

//Release the BlockingSenderDestination. 
                    finally
                    {
                        if(bsd != null)
                        {
                            bsd.release();
                        }
                    }
                }

            });

//Start the thread.
            t.start();
            
        }
    }

    private void BSDResponse(Message msg)
    {
        if (msg instanceof ByteMessage)
        {
            ByteMessage reply = (ByteMessage) msg;
            _result = (String) reply.getStringPayload();
        } else if(msg instanceof StreamMessage)
        {
            StreamMessage reply = (StreamMessage) msg;
            InputStream is = reply.getStreamPayload();
            byte[] data = null;
            try {
                data = net.rim.device.api.io.IOUtilities.streamToBytes(is);
            } catch (IOException e) {
                // Process the error.
            }
            if(data != null)
            {
                _result = new String(data);
            }
        }

        _app.invokeLater(new Runnable() {

            public void run() {
                _app.pushScreen(new HTTPOutputScreen(_result));
            }

        });

    }

}


class HTTPOutputScreen extends MainScreen 
{

    RichTextField _rtfOutput = new RichTextField();

    public HTTPOutputScreen(String message)
    {
        _rtfOutput.setText("Retrieving data. Please wait...");
        add(_rtfOutput);
        showContents(message);
    }

    // After the data has been retrieved, display it.
    public void showContents(final String result) 
    {
        UiApplication.getUiApplication().invokeLater(new Runnable() 
        {

            public void run() 
            {
                _rtfOutput.setText(result);
            }
        });
    }
}

Request data using a NonBlockingSenderDestination object

To request data using the NonBlockingSenderDestination class, create an object that implements the MessageListener interface. For more information, see "Implement the MessageListener interface".

import net.rim.device.api.io.URI;
import net.rim.device.api.io.messaging.*;
import net.rim.device.api.ui.*
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.system.Application;
import java.io.*;

public class NetworkSample extends UiApplication 
{
    public static void main(String[] args) 
    {
        NetworkSample app = new NetworkSample();
        app.enterEventDispatcher();
    }
    public NetworkSample() 
    {
        pushScreen(new NonBlockingSenderSample());
    }
}

class NonBlockingSenderSample extends MainScreen 
                                                 implements FieldChangeListener
{

    ButtonField _btnNonBlock = new ButtonField(Field.FIELD_HCENTER);

    private static UiApplication _app = UiApplication.getUiApplication();

    public NonBlockingSenderSample()
    {
        _btnNonBlock.setChangeListener(this);
        _btnNonBlock.setLabel("Fetch page");

        add(_btnNonBlock);
    }

    public void fieldChanged(Field button, int unused)
    {

        if(button == _btnNonBlock)
        {

//Create a NonBlockingSenderDestination object.
            NonBlockingSenderDestination destination = null;
            try
            {

//Create a URI object to pass to the DestinationFactory class.
                URI uri = URI.create("http://www.blackberry.com");

//Create a reference to your MessageListener.
                NBSDMsgListener responseListener = new NBSDMsgListener();

//Retrieve the NonBlockingSenderDestination object for your context, if one exists.
                destination = (NonBlockingSenderDestination)
                                  DestinationFactory.getSenderDestination
                                      ("CommAPISample", uri);

//If no NonBlockingSenderDestination exists, create one.
                if (destination == null)
                {
                    destination =
                        DestinationFactory.createNonBlockingSenderDestination
                            (new Context("CommAPISample"), uri, responseListener);
                }


//Send a message to the web service.
                destination.send();

            }

//Catch any errors that occur if the message could not be sent.
            catch(Exception e)
            {
                // process the error
            }

        }
    }

}

class NBSDMsgListener implements MessageListener 
{

    public void onMessage(Destination dest, Message msg) 
    {

        String payload = null;

        if (msg instanceof ByteMessage)
        {
            ByteMessage reply = (ByteMessage) msg;
            payload = (String) reply.getStringPayload();
        } else if(msg instanceof StreamMessage)
        {
            StreamMessage reply = (StreamMessage) msg;
            InputStream is = reply.getStreamPayload();
            byte[] data = null;
            try {
                data = net.rim.device.api.io.IOUtilities.streamToBytes(is);
            } catch (IOException e) {
            }
            if(data != null)
            {
                payload = new String(data);
            }
        }
        if(payload!=null)
        {
            synchronized(Application.getEventLock())
            {
                UiApplication.getUiApplication().pushScreen
                                                (new HTTPOutputScreen(payload));
            }


        }
    }

    public void onMessageCancelled(Destination arg0, int arg1) 
    {
        // Process message cancelled notification.
    }

    public void onMessageFailed(Destination arg0, MessageFailureException arg1) 
    {
        // Process message failed notification.
    }

}

class HTTPOutputScreen extends MainScreen 
{

    RichTextField _rtfOutput = new RichTextField();

    public HTTPOutputScreen(String message)
    {
        _rtfOutput.setText("Retrieving data. Please wait...");
        add(_rtfOutput);
        showContents(message);
    }

    // After the data has been retrieved, display it.
    public void showContents(final String result) {
        UiApplication.getUiApplication().invokeLater(new Runnable() 
        {

            public void run() 
            {
                _rtfOutput.setText(result);
            }
        });
    }
}

Release the NonBlockingSenderDestination when you are done processing the response.

Send data using a FireAndForgetDestination object

Import the required classes and interfaces.

import net.rim.device.api.io.messaging.*;
import net.rim.device.api.io.URI;

Create a URI object to pass to the DestinationFactory class.

URI uri = new URI("http://www.example.com");

Create a FireAndForgetDestination object.

FireAndForgetDestination ffd = null;

Retrieve the FireAndForgetDestination object for your context, if one exists.

try
{
    ffd = (FireAndForgetDestination) DestinationFactory.getSenderDestination
                                          ("MyContext", uri);

If no FireAndForgetDestination exists, create one.

    if(ffd == null)
    {
        ffd = DestinationFactory.createFireAndForgetDestination
                          (new Context("MyContext"), uri);
    }

Create a ByteMessage object and populate it with information to send to a web service.

    ByteMessage myMsg = ffd.createByteMessage();
    myMsg.setStringPayload("I love my BlackBerry smartphone!");

Cast your message as an HTTPMessage to set the HTTP method that you want to use.

    ((HttpMessage) myMsg).setMethod(HttpMessage.POST);

Send the message to the web service.

    ffd.sendNoResponse(myMsg);

Catch any errors that occur if the message could not be sent for some reason.

    catch (Exception e)
    {
        // Process the error
    }

Parsing a common Internet data format

You can configure a Destination object to return a Java object that contains data parsed from a standard format, such as JSON. To retrieve the data structure in a Java object, you should:
  • Specify a MessageProcessor object when you invoke DestinationFactory.create...().
  • Retrieve the response from your Destination.
  • Extract the data from the Message object that is returned in the response.

The following code sample demonstrates the three actions that are required to retrieve a Java object that contains a JSON data structure.

import net.rim.device.api.io.messaging.*
import net.rim.device.api.io.parser.json.*

// Specify a MessageProcessor when you create your Destination.
BlockingSenderDestination bsd = DestinationFactory(myContext, myURI,
                          new JSONMessageProcessor());

// Retrieve the response.
Message response = bsd.sendReceive();

// Extract the Java object that contains the JSON data structure
Object payload = response.getObjectPayload();

Parsing a JSON data structure

The following code sample demonstrates one way to parse a JSON data structure. You can use a similar process to parse JSON or other data formats that are provided by the Message Processing API.

import net.rim.device.api.io.URI;
import net.rim.device.api.io.messaging.*;
import net.rim.device.api.ui.*
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import java.io.*;
import org.json.me.*;

public class NetworkSample extends UiApplication 
{
    public static void main(String[] args) 
    {
        NetworkSample app = new NetworkSample();
        app.enterEventDispatcher();
    }
    public NetworkSample() 
    {
        pushScreen(new ParseJSONSample());
    }
}

//Define a MainScreen class that implements TreeFieldCallback interface.
class ParseJSONSample extends MainScreen implements FieldChangeListener
{

    ButtonField _btnJSON = new ButtonField(Field.FIELD_HCENTER);

    private static UiApplication _app = UiApplication.getUiApplication();

    public ParseJSONSample()
    {
        _btnJSON.setChangeListener(this);
        _btnJSON.setLabel("Fetch page");

        add(_btnJSON);
    }

    public void fieldChanged(Field button, int unused)
    {

        if(button == _btnJSON)
        {

            Thread t = new Thread(new Runnable() 
            {
                public void run()
                {
                    Message response = null;
                    String uriStr = "http://docs.blackberry.com/sampledata.json"; 
                    BlockingSenderDestination bsd = null;
                    try
                    {
                        bsd = (BlockingSenderDestination)
                                    DestinationFactory.getSenderDestination
                                        ("CommAPISample", URI.create(uriStr));
                        if(bsd == null)
                        {
                            bsd =
                              DestinationFactory.createBlockingSenderDestination
                                  (new Context("CommAPISample"),
                                   URI.create(uriStr), new JSONMessageProcessor()
                                   );
                        }

                        // Send message and wait for response
                        response = bsd.sendReceive();
                        _json = response.getObjectPayload();

                        if(_json != null)
                        {
                            _app.invokeLater(new Runnable() 
                            {

                                public void run() 
                                {
                                    _app.pushScreen(new JSONOutputScreen(_json));
                                }

                            });
                        }
                    }
                    catch(Exception e)
                    {
                        System.out.println(e.toString());
                    }
                    finally
                    {
                        if(bsd != null)
                        {
                            bsd.release();
                        }
                    }
                }


            });
            t.start();

        }

}

class JSONOutputScreen extends MainScreen implements TreeFieldCallback 
{

    private TreeField _treeField;

//Create a constuctor that accepts an Object as a parameter, 
//creates the UI, and initiates the parsing code.
    public JSONOutputScreen(Object JSONData)
    {
        _treeField = new TreeField(this, Field.FOCUSABLE);
        add(_treeField);
        setTree(JSONData);
    }

//Create an initializeTree() method to clear any existing data from the TreeField.
    void setTree(Object obj)
    {
        int parentNode = 0;

        _treeField.deleteAll();

//Determine whether the current node in the JSON object is a JSONArray or a JSONObject. 
//Invoke the appropriate populateTreeArray() method.
        try
        {
            if(obj instanceof JSONArray)
            {
                parentNode = populateTreeArray
                                  (_treeField, (JSONArray) obj, parentNode);
            }
            else if(obj instanceof JSONObject)
            {
                parentNode = populateTreeObject
                                 (_treeField, (JSONObject) obj, parentNode);
            }
        }

//Catch any errors, and specify where the TreeField should add new data.
        catch(JSONException e)
        {
            System.out.println(e.toString());
        }

        _treeField.setCurrentNode(parentNode);
    }

//Implement populateTreeArray(TreeField, JSONArray, int). 
    int populateTreeArray(TreeField tree, JSONArray o, int p) throws JSONException
    {
        Object temp;
        int newParent;

//Add a node to the TreeField. 
									newParent = tree.addChildNode(p, "Array " + p);

//Iterate through the elements in this node of the JSONArray. 

        for(int i = 0; i < o.length(); ++i)
        {

//Retrieve the current JSONArray. 
            temp = o.get(i);

//If the node is empty, go to the next node.
            if(temp == null || temp.toString().equalsIgnoreCase("null"))
            {
                continue;
            }

//If this node contains a nested JSON structure, parse the object recursively.
//Again, choose the most appropriate version of populateTreeArray().
            if(temp instanceof JSONArray)
            {
                 
                populateTreeArray(tree, (JSONArray) temp, newParent);
            }
            else if(temp instanceof JSONObject)
            {
                
                populateTreeObject(tree, (JSONObject) temp, newParent);
            }

//This node must contain data. Add the data to the tree. 
		          else
            { 
                newParent = tree.addSiblingNode(newParent, temp.toString());
            }
        }

        return newParent;
    }


//Change the method signature.
    int populateTreeObject(TreeField tree, JSONObject o, int p) throws JSONException
    {
        Object temp;

        int newParent = tree.addChildNode(p, "Object" + p);

//Create a JSONArray containing the names of the elements.
        JSONArray a = o.names();

//Iterate over the newly created JSONArray instead of the JSONObject passed as a parameter. 
        for(int i = 0; i < a.length(); ++i)
        {

//From the JSONObject,retrieve the value for each name in jsonArray.
            temp = o.get(a.getString(i));

            if(temp == null || temp.toString().equalsIgnoreCase("null"))
            {
                continue;
            }
            if(temp instanceof JSONArray)
            {
                populateTreeArray(tree, (JSONArray) temp, newParent);
            }
            else if(temp instanceof JSONObject)
            {
                populateTreeObject(tree, (JSONObject) temp, newParent);
            }
            else
            {

//Ensure that you add both the name and value to the tree.
                tree.addSiblingNode
                        (newParent, a.getString(i) + ": " + temp.toString());
            }
        }

        return newParent;
    }

//Implement DrawTreeItem().
    public void drawTreeItem(TreeField treeField, Graphics graphics, int node,
            int y, int width, int indent) 
    {
        if(treeField == _treeField)
        {
            Object cookie = _treeField.getCookie(node);
            if(cookie instanceof String)
            {
                String text = (String) cookie;
                graphics.drawText(text, indent, y, Graphics.ELLIPSIS, width);
            }
        }

    }

    public boolean onSavePrompt()
    {
        // Suppress the save dialog.
        return true;
    }

}

Sending login information to an HTTP server

A Destination object can supply login information, such as a user name and password, when a web server requests it. Login information is stored in the Context object that you supply when you create a Destination using the DestinationFactory class.

context = new Context("DemoContext", new CredentialsCollector() {
    public UsernamePasswordCredentials getBasicAuthenticationCredentials
        (String aeID, Hashtable properties) {
            // Provide or retrieve authentication credentials here. 
            // For example, you could display a dialog box to ask your user 
            // to enter a username and password, then return them from 
            // this method.
            return new UsernamePasswordCredentials("username", "password");
    }
});