.

End-To-End BlackBerry Application (Part 6)

July 15, 2008 18:01 by Jorge

In this sixth delivery of my end-to-end BlackBerry application walk-through, I will cover the following topics:

  • Creating a .NET http handler to send and receive information from the handheld application
  • Consuming the server-side business logic services from our http handler
  • Making requests from the handheld application and receiving data

While the previous articles of this series dealt with creating the Java application that will be installed on the handheld device, today I will be working on the server-side modules. Let’s take another look at our basic building blocks:

Building-Blocks1

The server-side modules consist of a .NET HTTP handler, a set of class libraries that contain the business logic and data access code, and a SQL Server database that will serve as the articles repository of our Knowledge Base application.

Creating The HTTP Handler

The mission of  the HTTP Handler is to extract the information from the HTTP requests made from the handheld, determine what type of action is required and ask the business logic layer to execute such actions. It will also append the results produced by the business logic to HTTP responses and send them to the handheld application.

In order for the handheld application and the handler to be able to talk to each other, all the commands that the handheld application can possibly send need to be defined within the handler as they were defined in the handheld:

// The commands the handheld can send us.
private const int CMD_SEARCH_ARTICLES = 1;
private const int CMD_GET_ARTICLES_BY_TAG = 2;
private const int CMD_GET_TAG_COUNTS = 3;

The keys identifying  each of the request parameters need to be defined as well:

// The request keys.
private const string KEY_COMMAND = "cmd";
private const string KEY_SEARCH_PHRASE = "sp";
private const string KEY_TAG = "tg";

KEY_SEARCH_PHRASE identifies the request parameter carrying the search phrase when a request to search the existing articles is made. KEY_TAG identifies the parameter carrying the tag name when the request is to retrieve the articles for a given tag.

Determining what to do is a matter of inspecting the request parameter marked with the KEY_COMMAND key:

string commandString = request.Form[KEY_COMMAND];
 
if (!int.TryParse(commandString, out currentCommand)) 
{
    // Bail if we don't receive a numeric command.
    return;
}
 
articlesServer = Shared.GetArticlesServer(context);
 
switch (currentCommand)
{
    case CMD_SEARCH_ARTICLES:
        string searchPhrase = request.Params[KEY_SEARCH_PHRASE];
        responseString = SearchArticles(searchPhrase);
        break;
    case CMD_GET_ARTICLES_BY_TAG:
        string tag = request.Params[KEY_TAG];
        responseString = GetArticlesForTag(tag);
        break;
    case CMD_GET_TAG_COUNTS:
        responseString = GetTagCounts();
        break;
    default:
        return;
}

Consuming The Business Logic Services

I won’t go into the details of the construction of the business logic and data access layers today, since they were covered in my End-to-end ExtJS application series. Something noteworthy, though, is the fact that these layers support storage of the articles in a file or in a SQL Server database. The code download for today’s article defaults to file-based storage, but you can run the included SQL script to install the database and point the business layer to it by changing the web application’s configuration file.

In the HTTP handler, SearchArticles(), GetArticlesForTag() and GetTagCounts() simply forward the requests to the business logic layer:

private string SearchArticles(string searchPhrase)
{
    Debug.Assert(searchPhrase != null);
    if (null == searchPhrase)
    {
        ExceptionPolicy.HandleException(
                new ArgumentNullException("searchPhrase"), 
                Shared.KB_EXCEPTION_PLCY);
    }
 
    string result = string.Empty;
 
    try
    {
        List<IArticle> articles = 
            articlesServer.GetArticlesForSearchPhrase(searchPhrase);
        if (null == articles) return 
                string.Empty;
        result = SerializeArticlesList(articles);
    }
    catch (Exception ex)
    {
        ExceptionPolicy.HandleException(ex, Shared.KB_EXCEPTION_PLCY);
    }
 
    return result;
}
private string GetArticlesForTag(string tag)
{
    Debug.Assert(tag != null);
    if (null == tag)
    {
        ExceptionPolicy.HandleException(
            new ArgumentNullException("tag"), 
            Shared.KB_EXCEPTION_PLCY);
    }
 
    string result = string.Empty;
 
    try
    {
 
        List<IArticle> articles = articlesServer.GetArticlesForTag(tag);
        if (null == articles) return
                string.Empty;
        result = SerializeArticlesList(articles);
    }
    catch (Exception ex)
    {
        ExceptionPolicy.HandleException(ex, Shared.KB_EXCEPTION_PLCY);
    }
 
    return result;
}
private string GetTagCounts()
{
    StringBuilder sb = new StringBuilder("");
 
    try
    {                
        Dictionary<string, int> tagCounts = articlesServer.GetTagCounts();
 
        if (null != tagCounts && tagCounts.Count > 0)
        {
            foreach (KeyValuePair<string, int> tagStat in tagCounts)
            {
                sb.Append(string.Format("{0}^~^{1}~^~", 
                    tagStat.Key, 
                    tagStat.Value));                       
            }
        }
 
    }
    catch (Exception ex)
    {
        ExceptionPolicy.HandleException(ex, Shared.KB_EXCEPTION_PLCY);
    }
    return sb.ToString();
}

After the business logic results are delivered to the handler I need to serialize the results according the formatting convention I had established when I wrote the handheld code. For example, this is the routine that converts a list of articles into a string that will be sent to the handheld as part of the HTTP response:

private string SerializeArticlesList(List<IArticle> articles)
{
    Debug.Assert(articles != null);
    if (null == articles)
    {
        ExceptionPolicy.HandleException(
            new ArgumentNullException("articles"), 
                Shared.KB_EXCEPTION_PLCY);
    }
 
    StringBuilder sb = new StringBuilder("");
    string body;
 
    foreach (IArticle article in articles)
    {
        // Decode the html characters in the body of the article.
        body = HttpUtility.HtmlDecode(HttpUtility.UrlDecode(article.Body));
        // Strip the html characters (We're using a RichTextField on the handheld,
        // which isn't capable yet of displaying html.
        body = Regex.Replace(body, @"<(.|\n)*?>", string.Empty);
 
        sb.Append(string.Format("{0}^~^{1}^~^{2}^~^{3}^~^", 
            article.Id.ToString(), 
            article.Title, 
            article.DateCreated.ToShortDateString(), 
            article.Author));
        sb.Append(string.Format("{0}^~^{1}~^~", 
            article.Tags, body));
    }
 
    return sb.ToString();
}

Did you notice that in the code above I’m also removing the Html characters from the body of the article? I have to do this because the field I’m using to display the body of the article on the handheld is not capable of rendering Html.

All that’s left now is to send the data to the handheld:

response.ContentType = "text/plain";
int contentLength = response.Output.Encoding.GetByteCount(responseString);
response.AppendHeader("content-length", contentLength.ToString());
response.Write(responseString);
response.End();

Well,  I know the walk through the server-side code went pretty fast. I encourage you to download the code for today’s post and check it out to see all the details. Also, reading the End-to-end ExtJS application post can give you more insight on the business logic and data access layers.

Making Requests From The Handheld Application And Receiving Data

Let’s return to the device-side code and ready it to connect to the HTTP handler. The first thing I will do is stop using the MockHTTPTransport instance and start using KbHTTPTransport. While MockHTTPTransport simply simulates an HTTP request to allow for testing of all the rendering logic on the device, KbHTTPTransport is the real deal. This is how I use it from the Articles Screen or the Tags Screen:

private void sendHttpRequest(String[] keys, String[] values) {
   
   articlesList.set(null);  // Show "No Articles" while we download.
    
   String url = DataStore.getAppServerUrl();
   // Make sure we can create an http request.
   // If the app. server URL has not been set, we cannot make any http requests.
    if (null == url || url.length() == 0) {
        Dialog.alert(resources.getString(
            KnowledgeBaseResource.ERR_INVALID_APP_SERVER_URL));
        return;
    }
    
    statusDlg.show();
    
    byte[] requestContents = TransportUtils.createPostData(keys, values);
    
    KbHTTPTransport transport = new KbHTTPTransport();
    transport.setHTTPTransportListener(this);
    transport.send(KbHTTPTransport.REQ_METHOD_POST, url, requestContents);        
    
}

At this point all the pieces are in place and I’m going to use the BlackBerry simulator and MDS simulator to test the application with real data. After firing up both simulators, I will check the Options Screen and make sure that I’m pointing to the right URL for my HTTP handler:

Options Screen

Back to the Main Screen, I choose Browse Tags:

image

And here I am getting real data from the handler:

image

Selecting a tag should bring back some articles:

image

And selecting an article should display its contents:

image

Conclusion

I hope you’ve found this series of posts helpful. I think the application is at a reasonable quality level where you can use its blocks as a foundation for your own projects. Although I’ll move on into other topics, I’m willing to come back to work on or talk more about any areas of your interest. Please let me know your thoughts. 

Downloads

Download the source code for this article from the Downloads page.

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

How to Build a Real-World BlackBerry Application

April 23, 2008 16:40 by Jorge

Quite a few readers have requested more information about development for BlackBerry devices. In this series of posts I will walk you through the creation of an end-to-end application that will be a BlackBerry version of the web application I talk about in these articles: End-to-end ExtJS application (Part 1) and End-to-end ExtJS application (Part 2).

In case you haven’t read the articles, the web application I built is a very simple Knowledge Base System. These are the basic usage scenarios I had established for it

  1. Browsing a collection of articles stored in a knowledge base repository
  2. Creation, edition or deletion of articles (any user can view, create, edit and delete any articles),
  3. View an article. The article’s visible attributes are
    • Title
    • Body
    • Tags, as a way to connect the article to specific topics
    • Author’s name
    • Date published

Requirements

For the BlackBerry application, I will skip the creation, edition and deletion of articles and focus on browsing and viewing existing articles. So, my first take at the usage scenarios produces this list

  1. Searching a collection of articles stored in a knowledge base repository,
    • By title,
    • By tags 
  2. View an article. The article’s visible attributes are
    • Title
    • Body
    • Tags, as a way to connect the article to specific topics
    • Author’s name
    • Date published

Building Blocks

Besides the BlackBerry application, I will use a .NET http handler on the server side, to channel all communications between the device and the articles database.


User Interface

I’ve found that when I enter the construction phase on a project of this kind, it always helps me if I have an idea of how the user interface is going to look. Keeping my “product owner” hat on, I am going to help my coder alter ego by putting together a few rough UI prototypes.

First comes the Home Screen. This will be the main screen of the application and I expect it to be a door into the different search features that will be available as well as the application settings.

 

Now to the Search Screen. This screen will allow our users to initiate an articles search by typing one or more words belonging to the article’s title.

The Browse Tags Screen will display a list of the existing tags in the database. Beside each tag there will be a count of the articles the tag applies to.

The Results Screen will show a list of articles that satisfy the criteria entered on the Search Screen. It will also allow our users to click on any listed article in order to view it.

The Article Screen will show the viewable attributes of the article that was selected on the Results Screen. This is where the user get’s to read the article.

The Options Screen will allow the user to change the application settings. In terms of settings, so far I can only think of the url our application will connect to in order to talk to its server counterpart, and the number of references to recently viewed articles to keep cached on the device.

 


Implementation

It looks like I can switch to “coder” mode and get started writing our device-side code. I will first take care of creating a stripped-down version of the application that does nothing but display the main user interface elements. This will allow me to validate my UI prototypes and serve as a foundation I can build upon later when I have to add the networking routines and the code that will take care of loading and saving the application settings. In this post I will create the Application Class and the Home Screen. I will tackle the rest of the screens in my next article.

The Development Environmet

The IDE I will be using is the BlackBerry JDE version 4.3.0. You can download the IDE as well as its documentation here.

The Application Class

Let’s begin with the Application Class. This class will be the entry point into our application and will be in charge of creating the Home Screen.

Worth highlighting is the constructor of the Class, which is where I create an instance of the Home Screen and push it to the display stack.

Home Screen

The Home Screen displays a list of search options.

One interesting detail here is that I'm extending the ObjectListField Class in order to be able to add a small icon to each of the search options.

The navigationClick method is where I’m going to determine what search option will be displayed.


What’s next

This is it for now. In my next article of this series, I will build the rest of the screens and lay the foundation for adding the networking code as well as the code to save a retrieve the application settings. Once I cover the device-side code, I will move to the server side and take care of the pieces that will handle the communications with the device.

Downloads

Download the source code for this article from the Downloads page.

 

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

End-to-end ExtJS application (Part 2)

April 12, 2008 16:14 by Jorge

I just updated my sample end-to-end ExtJS application. As a reminder, I had defined just a few usage scenarios that would keep the application at a very basic level

  1. Browsing a collection of articles stored in a knowledge base repository
  2. Creation, edition or deletion of articles (any user can view, create, edit and delete any articles),
  3. View an article. The article’s visible attributes are
    • Title
    • Body
    • Tags, as a way to connect the article to specific topics
    • Author’s name
    • Date published

What’s new

The main goal for this release was to switch to a SQL Server-based articles repository. As you can recall from Part 1, the articles were being maintained in a file.

The original building blocks 

 


 

Our building blocks after the update


What’s next

These are the changes I think I will be making in the future

  • Add pagination capabilities to the “articles list” GridPanel
  • Move string to resources file so it’s easier to localize the application
  • Create user extensions for the main components

Downloads

Download the source code for this article from the Downloads page.

Important: Remember to open your web.config file and enter the correct values for your database connection string before running the sample.

 

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