.

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

June 23, 2008 21:45 by Jorge

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.

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:

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

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.

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

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 from the Downloads page.

Actions: E-mail | Permalink | Comments (1) | Trackback

Related posts


Comments


miamicoder.com

July 7, 2008 20:53

Pingback from miamicoder.com

End-To-End BlackBerry Application (Part 5)

Add comment


  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview



August 19, 2008 17:34