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: KnowledgeBaseBB-6-24-08.zip


