Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

End-to-End Real World BlackBerry Application, Part 4

0.00/5 (No votes)
4 Aug 2008 4  
End-to-end real world BlackBerry application walkthrough, Part 4.

Introduction

In the last three articles, I’ve been walking you through the creation of an end-to-end BlackBerry application that will serve as a mobile front-end to my Knowledge Base sample web application.

In the third part of this series, I finished the areas of the application that store and retrieve data from the device’s memory. Together with storing data on the device, the ability to use the network is vital for most applications. Today, I will be showing you how the application will communicate with its server-side service.

But first, let’s do a little refactoring.

The Options Class is Now the DataStore Class

Yes, after working with the Options class for a while, I decided that, since it not just deals with application settings, a better name for it would be DataStore. “DataStore” better explains the intent of the class.

Making HTTP Requests

There is a plethora of information regarding HTTP connections. I will leave most of it out of this article, and focus only on what’s strictly needed for our application to be able to send HTTP requests and consume HTTP responses.

Two things I should mention are the javax.microedition.io.HttpConnection interface, which defines the necessary methods and constants for an HTTP connection, and javax.microedition.io.Connector, the Factory class for creating connections.

For my networking tasks, I have reused and adapted some code that I obtained from the existing BlackBerry sample code online. The bulk of the HTTP handling code will conform to contracts defined in two separate interfaces, HTTPTransport and HTTPTransportListener.

HTTPTransport Interface and the KbHTTPTransport Class

HTTPTransport is an interface that defines the methods for creating HTTP requests.

/**
 * Defines the methods to send HTTP requests. 
 */
public interface HTTPTransport {
    
    public void send(final String requestMethod, 
        final String URL, final String requestData);
    public void send(final String requestMethod, 
        final String URL, final String requestData, 
        final String[] headerKeys, final String[] headerValues);
    public void setHTTPTransportListener(HTTPTransportListener t);
    public void removeHTTPTransportListener();
    
}

KbHTTPTransport is a helper class which can make HTTP requests by implementing the methods defined in HTTPTransport. KbHTTPTransport will notify an attached HTTPTransportListener with the response to the request. HTTPTransportListener is an interface that defines the methods a class must have in order to process the response from an HTTP request.

Implementing HTTPTransportListener Inside the Articles Screen

So far, the only place in the application where there’s a need to send HTTP requests is the Articles Screen. Implementing HTTPTransportListener enables our Articles Screen to process HTTP responses:

public void processResponse(final int HTTPResponseCode, final String data) {
    UiApplication.getUiApplication().invokeLater(new Runnable() {
        public void run()
        {
            switch (HTTPResponseCode) {
        
                case (KbHTTPTransport.NOT_IN_COVERAGE): 
                    Dialog.alert("Not in coverage.");
                    break;
                case HttpConnection.HTTP_OK:
                    parseResponseData(data);
                    break;
                // TODO: Check all the http error codes you are interested in.
                // for example HttpConnection.HTTP_FORBIDDEN
                default:
                Dialog.alert("There was an error with the request.");
                break;

            }
        }
    });
}

Choosing a Transmission Format

From the multiple formats for transmitting serialized data over the net, namely XML, binary, etc., I decided to send and receive data in the form of strings, where the contents of a response are a custom-formatted strings that represent a list of articles.

A formatted list of articles would look like this:

id^~^title^~^dateCreated^~^author^~^tag1,tag2,...^~^contents~^~

where the sequence “^~^” separates the fields of an article, and the sequence “~^~” separates one article from the next.

Notice how this is a pretty simple format that is both easy to use and light in terms of the number of characters transmitted (think about how verbose XML is).

The parseResponseData() routine is where we de-serialize the response string and create a list of Article instances.

private void parseResponseData(String data) {
        
    // Parse out each article from the string data
    // Format: id^~^title^~^dateCreated^~^author^~^
    //tag1,tag2,...^~^contents~^~<NEXT RECORD>
    
    Vector articlesVector = new Vector();
    int index = 0;
    int length = data.length();
    while (index != -1 && index < length - 1){
        
        if (index == 0) index = -1;
        
        Article article = new Article();
          
        article.id = data.substring(++index , 
                index = data.indexOf(FIELD_SEPARATOR, index));
        index += 3;
        article.title = data.substring(index , 
                index = data.indexOf(FIELD_SEPARATOR, index));
        index += 3;
        article.dateCreated = data.substring(index, 
                index = data.indexOf(FIELD_SEPARATOR, index));
        index += 3;
        article.author = data.substring(index, 
                index = data.indexOf(FIELD_SEPARATOR, index));
        index += 3;
        String tags = data.substring(index, 
                index = data.indexOf(FIELD_SEPARATOR, index));
        article.tags  = StringUtilities.stringToWords(tags);
        index += 3;
        article.contents = data.substring(index, 
                index = data.indexOf(RECORD_SEPARATOR, index)); 
        index += 2;           
        articlesVector.addElement(article);
    }
    
    articles = new Article[articlesVector.size()];
    articlesVector.copyInto(articles);
    articlesList.set(articles);
}

Testing the Networking Code

At this point in time, I need to be able to test my networking code without the presence of the server side code (it doesn’t exist yet). In order to achieve this, I have built an implementation of HTTPTransport called MockHTTPTransport, which creates different kinds of responses that simulate the scenarios that could occur when working with HTTP requests – timeouts, failed authentication, etc.

class MockHTTPTransport implements HTTPTransport {
    
    private HTTPTransportListener listener = null;
     
    MockHTTPTransport() {    }
    
    public void setHTTPTransportListener(HTTPTransportListener t){
        listener = t;
    }    
    
    public void removeHTTPTransportListener(){
        listener = null;
    }    
    
    public void send(final String requestMethod, final String URL, 
        final String requestData){
        send(requestMethod, URL, requestData, null, null);;
    }
    
    public void send(final String requestMethod, final String URL, 
        final String requestData, final String[] headerKeys, 
        final String[] headerValues) {                                           
        
        // Since this is just for testing purposes, 
        // in here we will return a list or articles, 
        // as if we had just gotten them via an http request.
        createArticlesListResponse();     
                                           
    }
    private void createArticlesListResponse() {        
        // Create the articles.
        Article[] articles = new Article[15];
        Article article;
        for (int i = 0; i < 15; i++) {          
          article = new Article();
          article.id = String.valueOf(i);
          article.title = "Dummy article " + Integer.toString(i);
          article.author = "doej";
          article.contents = "This is a test article";
          article.tags = new String[] {"tag 1", "tag 2", "tag 3"};
          article.dateCreated = "01/01/2008";
          articles[i] = article;          
        }
        String FIELD_SEPARATOR = "^~^";
        String RECORD_SEPARATOR = "~^~";        
        //Create the the simulated response data 
        //with the information from the articles.
        StringBuffer response = new StringBuffer();
        for (int i = 0; i < articles.length; i++) {            
            article = articles[i];
            StringBuffer tags = new StringBuffer();
            for (int j = 0; j < article.tags.length; j++) {
                tags.append(article.tags[j] + ",");
            }
            // Remove the last ","
            tags.deleteCharAt(tags.length() - 1);            
            // Format: id^~^title^~^dateCreated^~^author^~^
            //tag1,tag2,...^~^contents~^~<NEXT RECORD>
            response.append(article.id + FIELD_SEPARATOR + 
                article.title + FIELD_SEPARATOR +
                article.dateCreated + FIELD_SEPARATOR + article.author + 
                FIELD_SEPARATOR + tags + FIELD_SEPARATOR + article.contents +
                RECORD_SEPARATOR);            
        }         
        int httpResponseCode  = HttpConnection.HTTP_OK;        
        // Introduce a delay to simulate latency.
        try {
            Thread.sleep(1500);
        } catch (InterruptedException ex) {}        
        listener.processResponse(httpResponseCode,response.toString());    
    }

What’s Next

The next article of this series will be dedicated to the server side of the application. On the server side, I will put together the code to handle incoming HTTP requests, retrieve information from the database, and send responses back to the application on the BlackBerry device.

Previous Articles

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here