How to Build a Real-World BlackBerry Application (Part 4)

For the past three posts 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 only deals with application settings, a better name for it would be DataStore. “DataStore” explains better 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.


title=”Click for expanding..”>Java-Code: HTTPTransport
001/**
002 * Defines the methods to send HTTP requests.
003 */
004public interface HTTPTransport {
005
006    public void send(final String requestMethod,
007        final String URL, final String requestData);
008    public void send(final String requestMethod,
009        final String URL, final String requestData,
010        final String[] headerKeys, final String[] headerValues);
011    public void setHTTPTransportListener(HTTPTransportListener t);
012    public void removeHTTPTransportListener();
013
014}

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:


title=”Click for expanding..”>Java-Code: HTTPTransportListener implementation
001
002 class ArticlesScreen extends MainScreen implements HTTPTransportListener {
003
004	.
005	.
006	.
007
008    public void processResponse(final int HTTPResponseCode, final String data) {
009        UiApplication.getUiApplication().invokeLater(new Runnable() {
010            public void run()
011            {
012                switch (HTTPResponseCode) {
013
014                    case (KbHTTPTransport.NOT_IN_COVERAGE):
015                        Dialog.alert("Not in coverage.");
016                        break;
017                    case HttpConnection.HTTP_OK:
018                        parseResponseData(data);
019                        break;
020                    // TODO: Check all the http error codes you are interested in.
021                    // for example HttpConnection.HTTP_FORBIDDEN
022                    default:
023                    Dialog.alert("There was an error with the request.");
024                    break;
025
026                    }
027            }
028        });
029
030    }
031 

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 the data in the form of strings, where the contents of a response are a custom-formatted string that represents 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 characters transmitted (think about how verbose XML is).

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


title=”Click for expanding..”>Java-Code: parseResponseData
001
002    private void parseResponseData(String data) {
003
004        // Parse out each article from the string data
005        // Format: id^~^title^~^dateCreated^~^author^~^
006        //tag1,tag2,...^~^contents~^~<NEXT RECORD>
007
008        Vector articlesVector = new Vector();
009        int index = 0;
010        int length = data.length();
011        while (index != -1 && index < length - 1){
012
013            if (index == 0) index = -1;
014
015            Article article = new Article();
016
017            article.id = data.substring(++index ,
018                    index = data.indexOf(FIELD_SEPARATOR, index));
019            index += 3;
020            article.title = data.substring(index ,
021                    index = data.indexOf(FIELD_SEPARATOR, index));
022            index += 3;
023            article.dateCreated = data.substring(index,
024                    index = data.indexOf(FIELD_SEPARATOR, index));
025            index += 3;
026            article.author = data.substring(index,
027                    index = data.indexOf(FIELD_SEPARATOR, index));
028            index += 3;
029            String tags = data.substring(index,
030                    index = data.indexOf(FIELD_SEPARATOR, index));
031            article.tags  = StringUtilities.stringToWords(tags);
032            index += 3;
033            article.contents = data.substring(index,
034                    index = data.indexOf(RECORD_SEPARATOR, index));
035            index += 2;
036            articlesVector.addElement(article);
037        }
038
039        articles = new Article[articlesVector.size()];
040        articlesVector.copyInto(articles);
041        articlesList.set(articles);
042    }
043 

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, MockHTTPTransport, which creates different kinds of responses that simulate the scenarios that could occur when working with HTTP requests – timeouts, failed authentication, etc.


title=”Click for expanding..”>Java-Code: MockHTTPTransport
001
002 /**
003 * Helper to test the network functionality in the Articles Screen without
004 * having a server side application.
005 */
006 class MockHTTPTransport implements HTTPTransport {
007
008    private HTTPTransportListener listener = null;
009
010    MockHTTPTransport() {    }
011
012    public void setHTTPTransportListener(HTTPTransportListener t){
013        listener = t;
014    }
015
016    public void removeHTTPTransportListener(){
017        listener = null;
018    }
019
020    public void send(final String requestMethod, final String URL,
021        final String requestData){
022        send(requestMethod, URL, requestData, null, null);;
023    }
024
025    public void send(final String requestMethod, final String URL,
026        final String requestData, final String[] headerKeys,
027        final String[] headerValues) {
028
029        // Since this is just for testing purposes, 
030        // in here we will return a list or articles, 
031        // as if we had just gotten them via an http request.
032        createArticlesListResponse();
033
034    }
035 


title=”Click for expanding..”>Java-Code: createArticlesListResponse()
001
002    private void createArticlesListResponse() {
003        // Create the articles.
004        Article[] articles = new Article[15];
005        Article article;
006        for (int i = 0; i < 15; i++) {
007          article = new Article();
008          article.id = String.valueOf(i);
009          article.title = "Dummy article " + Integer.toString(i);
010          article.author = "ramonj";
011          article.contents = "This is a test article";
012          article.tags = new String[] {"tag 1", "tag 2", "tag 3"};
013          article.dateCreated = "01/01/2008";
014          articles[i] = article;
015        }
016        String FIELD_SEPARATOR = "^~^";
017        String RECORD_SEPARATOR = "~^~";
018        //Create the the simulated response data 
019        //with the information from the articles.
020        StringBuffer response = new StringBuffer();
021        for (int i = 0; i < articles.length; i++) {
022            article = articles[i];
023            StringBuffer tags = new StringBuffer();
024            for (int j = 0; j < article.tags.length; j++) {
025                tags.append(article.tags[j] + ",");
026            }
027            // Remove the last ","
028            tags.deleteCharAt(tags.length() - 1);
029            // Format: id^~^title^~^dateCreated^~^author^~^
030            //tag1,tag2,...^~^contents~^~<NEXT RECORD>
031            response.append(article.id + FIELD_SEPARATOR +
032                article.title + FIELD_SEPARATOR +
033                article.dateCreated + FIELD_SEPARATOR + article.author +
034                FIELD_SEPARATOR + tags + FIELD_SEPARATOR + article.contents +
035                RECORD_SEPARATOR);
036        }
037        int httpResponseCode  = HttpConnection.HTTP_OK;
038        // Introduce a delay to simulate latency.
039        try {
040            Thread.sleep(1500);
041        } catch (InterruptedException ex) {}
042        listener.processResponse(httpResponseCode,response.toString());
043    }
044
045 

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, retrieving information from the database and sending responses back to the application on the BlackBerry device.

Downloads

Download the source code for this article: KnowledgeBaseBB-6-24-08.zip

About Jorge

Jorge is the author of Building a Sencha Touch Application, How to Build a jQuery Mobile Application, and the Ext JS 3.0 Cookbook. He runs a software development and developer education shop that focuses on mobile, web and desktop technologies.
If you'd like to work with Jorge, contact him at ramonj[AT]miamicoder.com.

Speak Your Mind

*