Working with Worklight, Part 2: Developing structured modules and using the Encrypted Offline Cache feature in IBM Worklight

Layering your mobile app with structure, functionality, and security

This series of articles introduces the IBM® Worklight® platform by showing how you can build mobile applications that leverage a variety of IBM software products. Part 2 continues to describe the process of developing a Worklight application, showing some best practices for building hybrid apps, and featuring Worklight’s Encrypted Offline Cache functionality.

Carlos Andreu , Software Developer, IBM

Carlos Andreu is a Software Developer in IBM Software Group. He is currently working on the creation of a framework to build Hybrid, Android and iOS applications. His interests range from following the latest trends and tech blogs, to reading, television, and enjoying to all kinds of music. You can learn more about him at http://dev.yapr.org/carlosandreu.



Jeremy Nortey, Software Developer, IBM

Jeremy Nortey is a Software Developer for the IBM Mobile Foundation within Software Group. He develops software and quality assurance for mobile solutions. He specializes in iOS and dabbles in building native apps for the iPhone in his spare time. His hobbies include soccer and running.



Raj Balasubramanian, Product Architect, IBM

Raj Balasubramanian is a Consulting IT Architect for IBM Software Group. He works on customer engagements delivering application and infrastructure related projects. His interests range from anything technical to history and physics. During his copious spare time, he enjoys dating his wife and talking about robots with his sons. You can read about his technical and personal escapades on his personal blog Gurukulam.



25 July 2012

Also available in Chinese Russian Japanese Vietnamese Portuguese Spanish

Introduction

IBM Worklight, part of the IBM Mobile Foundation provides a robust platform for rapidly building mobile applications, while leveraging web-based technologies that can run across multiple device platforms. This article picks up where Part 1 left off in the process of developing a fully functional, self-contained mobile app, called "Todo," which enables a mobile user to build and maintain a to-do list of tasks. In the process, you’ll learn about the Encrypted Offline Cache, a security measure of the Worklight client runtime that protects sensitive information from malware attacks and device theft.

Get Worklight now

Download IBM Worklight Developer Edition 5.0 now at no cost, and with no expiration date!

By now, you should have IBM Worklight Studio setup in your Eclipse IDE, and you should be familiar with how to deploy a simple "Hello World" type application on iOS and Android. We’ll start with the Todo app that you began to develop in Part 1. Download the initial app you created in Part 1 and import it into your Worklight Studio environment. (Alternatively, you can download the Todo app project files included with this article.)


Developing the app

Using the sample application

The sample application described here is presented as an exercise for example purposes only. Because the bulk of the application logic will be in JavaScript™ (specifically using JQuery), best practices in structuring the application logic for better readability, reliability, and consistency will be highlighted, as will practices regarding using namespace and more.

Figure 1 illustrates the general flow of the user running the Todo mobile application. To summarize, the user would:

  1. Open the app.
  2. Enter a passcode to securely store offline data, and tap Start to proceed to the second panel.
  3. Enter any text that represents a new “to do" item in the first field, then add it to the list by tapping the Add Item button.
  4. Mark an item as "done" by tapping the item in the list, making it selected. Tap Remove Done to delete all items marked done.
  5. Filter the items displayed on the panel by typing all or part of an item’s name inside the second text field, then tap Filter Items....
Figure 1. Sample app panels
Figure 1. Sample app panels

Your first step in adding this functionality to your app is to divide your code into modules that have specific responsibilities within the application. Todo will have these modules (Figure 2):

  • Constant module gets and sets various constants you will use in your application.
  • List module is responsible for storing the list for the current session and handling events, such as adding a new item to the list, marking items as done, and removing items that are marked done.
  • Vault module is tasked with encrypting and decrypting the list. This is where you will leverage Worklight’s Encrypted Offline Cache feature.
Figure 2. Modules and their interactions
Figure 2. Modules and their interactions

For structuring your code, you will leverage the common and popular Module Pattern, from the JavaScript world (see Resources). Listing 1 shows the skeleton of a module. You assign an auto-executing function (or immediate function) to an object (Module1) that’s contained in your namespace (MYAPP). It’s a good idea to pass things like the global object (window, for most of the client-side JavaScript) and vendor libraries (like jQuery, so you can use $ inside your module, even if something else uses $ outside the module, like Prototype.js or another library). It’s also a good practice to list dependencies and assign local variables to your dependencies because it’s quicker to access local variables than it is to search key value pairs.

For example:

var eoc = WL.EncryptedCache; eoc.open()

is better than making JavaScript search for the WL object, and then search for the EncryptedCache key that points to another object that contains the open function you want to call every time you need to call that function inside one of your modules.

Listing 1. Module Pattern skeleton
MYAPP.Module1 = (function (global, $) { 
//List dependencies: jQuery 1.7.2

//List private variables

//List private functions
var _init = function () {
console.log("I'm ready!");
}

//List one time initialization procedures 

//public API
return {
init : _init
};

}(window, jQuery)); //MYAPP.Module1

This is a good point to bring up some smart style conventions. Upper case characters are used in these code samples for constants, and underscore characters are added in front of private functions to distinguish them from private variables. You can extend this convention to leverage the “single var pattern," where a single variable (var) is declared at the top of every function that requires variables. This is done because JavaScript will "hoist" variables to the top when code is executed (Listing 2), and because forgetting to use var sometimes produces undesired results, such as overwriting a global variable with the same name.

Listing 2. Example of hoisting
//Example of Hoisting 
myname = "global";

function func() {
alert(myname); //returns: "undefined" 
var myname = "local";
alert(myname); //returns: "local"

There is an underlying construct called closure, which powers the modules (see Resources). In JavaScript, closure refers to a local variable for a function that is kept alive after the function has returned. This closely relates to scoping in JavaScript, which is defined by function. For example, Listing 1 shows you an example of closure in action. Here, _init is a private function that is not accessible outside the auto-executing function assigned to MYAPP.Module1, but you return an object that has a reference to that private function; this way, you can easily access it like MYAPP.Module1.init(). This can be accomplished due to closure.

JavaScript is an event-oriented programming language, akin to the Observer Pattern described in virtually every programming patterns book. In JavaScript scripts, events are fired every time the user scrolls, clicks on an HTML tag, or hovers over a link, to name a few examples. Events can be listened to, and you can trigger your own events.

Separation of concerns is another important practice to follow, which means keeping the markup, style, and application logic separate. Your HTML code should describe only the structure of your application; inline JavaScript functions in HTML is not desirable. You can achieve this by using the event-driven coding style, in which the specific element that would need to have the inline call is instead observed for the specific event that will trigger the necessary action. This enables you have the application logic in only one place, in the JavaScript, and not in multiple places throughout the HTML. Similarly, you should avoid writing HTML as part of the JavaScript and use templates instead (see Resources).


Constant module

Start by defining your namespace (Listing 3). For the sample Todo app, call your namespace "TD." The namespace is essentially an object that will hold other objects, all pertaining to your app. It’s possible that as your application grows, TD will already be defined in the global namespace. Use the single var pattern to create a TD object if one is not already available. This namespace function will ensure consistency in method invocation: invoking TD.namespace(TD.module1) will add an object called module1 to TD. You will see how you can declare the TD namespace and use it to cascade objects under the TD namespace as needed.

Listing 3. Namespace function
/**********************************************************************************
* TD NAMESPACE
**********************************************************************************/
var TD = TD || {};

TD.namespace = function (ns_string) { 
var parts = ns_string.split('.'),
parent = TD, 
i;

// strip redundant leading global 
if (parts[0] === "TD") {
parts = parts.slice(1); 
}

for (i = 0; i < parts.length; i += 1) {
// create a property if it doesn't exist
if (typeof parent[parts[i]] === "undefined") {
parent[parts[i]] = {}; 
}
parent = parent[parts[i]]; 
}

return parent; 
};

In Figure 3, you can see that TD.Constant (your Constant module) does not have any private members. It will only return values via what we will call the Public API (it’s a simple key value pair created using an object literal). Similarly, the Todo items key is used for Encrypted Offline Cache. The encrypt and decrypt values are simple boolean values that will eventually tell your Vault module if you want to encrypt or decrypt.

Figure 3. Modules elements
Figure 3. Modules and their interactions

List module

As shown in Figure 1 and Listing 4, the second panel of the app is essentially the appllication main page. It contains:

  • A logo on the header.
  • A text field (id="new-todo") that will be used to add new items.
  • A button to add new items (id="add").
  • A button to delete all items maked done (id="delete").
  • An unordered list to append the item list (id="todo-list").
  • A div tag (id="no_items") to display text when the list is empty.

Also notice that you get data filtering for free by adding a data-filter=’true’ property to your <ul> tag (see Resources). (http://jquerymobile.com/demos/1.1.0/docs/lists/index.html).

Listing 4. Main panel HTML
<!-------------------------- MAIN PAGE  -------------------------->
<div data-role="page" id="main" >

<!-- <div data-role="header"><h1>Todo App</h1></div> -->
<img class="centerimg" src="images/logonobg.png"/>

<div data-role="content" >

<input type="text" name="new-todo" id="new-todo" 
placeholder="Write your tasks here..." />

<div class="controls" data-role="controlgroup" data-type="horizontal">
<a href="#" id="add" data-role="button" data-icon="plus">Add New</a> 
<a href="#" id="delete" data-role="button" data-icon="delete">Delete Done</a>
</div>

<ul id="todo-list" data-role="listview" data-filter="true" data-inset="true" >
</ul><!-- /todo-list -->

<div class="center" id="no_items"></div>

</div>
<!-- /content -->
</div>
<!-- /page -->

For your task list, you will store items in a list array. For example:

[{content: “myTodo Item 1", done: false},
{content: “myTodo Item 2", done: true}].

It’s just a simple array with key value pairs (JavaScript objects) that have a string for the item’s name and a Boolean value to keeps track of whether an item is done or not.

As shown in Figure 3, TD.List (your List module) contains a private method defined (_encrypt) that will encrypt the list (a private array called ‘list’) calling your Vault module's encrypt method from its public API. You also have _item_template, which is a function generated from a template to display items defined inside your HTML document; you need to pass an object that has ‘item’ for the key and the list array.

An exercise

As an exercise, you might want to perform more elaborate type checking (for example, check if item.done returns a Boolean, check against null, and so on).

The private function _add is going to check if item.content is not empty or undefined, and whether something is returned when you call item.done. Remember that variables that have not been assigned a value by default will return "undefined."

Listing 5. _add function
_add =  function (item) {
if (item.content !== 'undefined' && item.done !== 'undefined' && item.content.length > 0)
{
list.push(item);
}
},// add item

The _refresh_list function dynamically runs a map function on the list array and add a new element to every object stored in that array. The rest of the function clears the list, appends the result of the template generated based on the list to the unordered list (ul) in the HTML, and refreshes the view. This latter method call is jQuery Mobile specific to refresh the styling for the list.

Listing 6. _refresh_list function
_refresh_list = function () {

$.map(list, function (item, i) {
item.index = i;
});

list_ul.empty();
list_ul.append(_item_template({item : list}));
list_ul.listview('refresh');

if (list.length < 1) {
no_items.text('No items.');
} else {
no_items.text('');
}

}; // refresh list

Another exercise

You might want to change this approach by using a different data structure and a different algorithm to generate and keep track of IDs. The goal is to not need to use the map function to iterate over the whole list and generate IDs, and not need to clear and re-append the whole list every time you add or remove an item.

Next, you will attach actions to events. If you’re familiar with jQuery, you might be used to seeing or using calls like bind(), live(), and delegate(). In this example, on() is used exclusively, because after jQuery 1.7.0 those bind, live, and delegate methods are just wrappers for on(). Also, $(this) is “cached" into a local variable called $this because, ideally, you want to use that jQuery function as little as possible and limit the amount of times you dive into the DOM (Document Object Module) because it’s a very costly operation. Notice that we toggle the boolean value that describes if the item is done or not, and add or remove a class called “done" defined in the stylesheet (.css file). Finally, you encrypt() the list to persist, even if you immediately close the application after clicking on an item to mark it done.

Listing 7. Event attachments inside TD.List
add_btn.on('click', function () {

_add({content : new_item.val(), 
done: false });

new_item.val('');
_refresh_list();

_encrypt();

}); // add btn

list_ul.on('click', 'li', function () {

var $this = $(this),
$item = $this.find('a'),
index = $item.attr('id'), 
current_item = list[index];

current_item.done = !(current_item.done);

if (current_item.done) {
$item.addClass('done');
} else {
$item.removeClass('done');
}

_encrypt();

}); // list item

delete_btn.on('click', function () { 
var i = list.length;

while (i--) {
if (list[i].done) {
list.remove(i);
}
}

_refresh_list();

_encrypt();

});// delete btn

A similar treatment is applied to the delete button, the code for which you can view in Worklight Studio.

The public API for your List module is very simple; you can get the current list you’re working with, set a new list and work with that, and refresh the currently set list. You call these methods by invoking the TD namespace, followed by the module’s name, and, lastly, one of the keys from the object that is returned by your module.

For example:

TD.List.get(), TD.List.set([]), TD.List.refresh()

would all be valid, while:

TD.List._refresh_list(), TD.List._add()

are not, because those functions can only be called inside the module (remember, functions create scope) or by privileged members (like the object that’s returned inside your module).

Listing 8. TD.List Public API
//public API
return {
get : function () {
return list;
},
set : function (new_list) {
list = new_list;
},
refresh : function () {
_refresh_list();
}
};

Vault module

The TD.Vault module is a wrapper for Worklight’s Encrypted Offline Cache (EOC) functionality. Building on the local storage in HTML5, EOC is a way to store persistent data without using cookies. EOC provides methods to open and close, and then to read and write values when open. The security details behind EOC is beyond the scope of this article, but in a nutshell, EOC leverages a user password to encrypt the data. Hence, the HTML code that’s relevant to this particular module is a page (the first panel in Figure 1) that contains:

  • A header image with logo or application name.
  • A field for the passcode (id=’passcode’).
  • A button (id=’send_passcode’) to submit that passcode.
Listing 9. HTML for passcode page
<!-------------------------- PASSCODE PAGE  -------------------------->
<div data-role="page">

<img class="centerimg" src="images/logonobg.png"/>

<div data-role="content">

<div class="center" id="invalid_passcode"></div>

<ul data-role="listview" data-inset="true">
<li data-role="fieldcontain">
<label for="passcode">Enter Passcode:</label> 
<input type="text" name="passcode" id="passcode" value="" placeholder="Your passcode" />
</li>
</ul>

<a id="send_passcode" href="#" data-role="button" data-theme="a">Start</a>
</div>
<!-- /content -->

</div>
<!-- /page -->

Start your JavaScript code by passing some global variables to your auto-executing function, such as jQuery (redefined as $) and WL (Worklight’s namespace, redefined as WL). You then "cache" your dependencies by assigning local variables to them. This ensures that you can easily call wl.EncryptedCache.open (rather than pass the WL namespace as a parameter to the module) and then cache wl.EncryptedCache in a local variable called eoc. Next, private variables such as KEY stores the passphrase the user enters, and some DOM calls are saved for the passcode button, passcode field, and a div that displays an error message if the passcode is invalid (Listing 10).

Listing 10. TD.Vault module, dependencies and private variables
TD.namespace('TD.Vault');
TD.Vault = (function ($, wl) { 
//dependencies
var eoc = wl.EncryptedCache,
log = wl.Logger,
list_obj = TD.List,
CONST = TD.Constant,

//private variables
KEY = "",
send_passcode_btn = $('#send_passcode'),
passcode_fld = $('#passcode'),
invalid_passcode_div = $('#invalid_passcode'),

A final exercise

You might want to check the Worklight documentation and implement error-specific handling based on the status code returned by the onErrorHandler callback function.

Next, you have some private variables, such as _error, which simply logs when you receive an error callback. The _setData and _getData methods specify how you get and set the data you are going to encrypt and decrypt (Listing 11).

Listing 11. _error, _setData and _getData functions
//private functions
_error = function () {
log.debug("error");
},

_setData = function (new_list) {
if (new_list) {
list_obj.set(new_list);
list_obj.refresh();
} 
},

_getData = function () {
return list_obj.get();
},

The event definition is similar to that in TD.List, where you attach send_passcode_btn on click, which simply assigns the passcode the user entered upon starting up the application to the private variable KEY, if the input length is at least 1 character (Listing 12).

Listing 12. Send Passcode Button Event Attachment
send_passcode_btn.on('click', function () {

var passcode = passcode_fld.val();

if (passcode.length > 0) {
KEY = passcode;

_decrypt();

$.mobile.changePage("#main", { transition: CONST.DEFAULT_TRANSITION });

} else {
passcode_fld.val('');
invalid_passcode_div.text('Invalid Passcode.');
}

});

Next, you decrypt the contents of the EOC by calling private variable _decrypt(). This calls _open with a constant (CONST.DECRYPT) that indicates that you are going to decrypt after you open the encrypted cache. The _open function triggers the event eoc-open and sends the action (decrypt) to _read(). You will then try to read the encrypted cache with the key the user provided. At this point, _setData is called with the data you got back parsed back into a JavaScript array with parseJSON (that array contains a key value pair that describes a single item on every index of the array). If you got something back from the cache, you call set on the List module to set the list you got back as the new list. Finally, the list HTML element is refreshed by calling refresh from TD.List’s public API.

Listing 13. _close, _write, _read, _encrypt, _decrypt functions and an ‘eoc-open’ event listener
_close = function () {
var onCompleteHandler = function () { 
$.publish('eoc-closed'); 
};

//function(onCompleteHandler, onErrorHandler)
eoc.close(onCompleteHandler, _error);
},

_write = function () {
var data = JSON.stringify(_getData());

//function(key, data, onCompleteHandler, onErrorHandler)
eoc.write(CONST.TODO_ITEMS_KEY, data, _close, _error); 
},

_read = function () {
var onCompleteHandler = function (data) {
_setData($.parseJSON(data)); 
_close(); 
};

//function(key, onCompleteHandler, onErrorHandler)
eoc.read(CONST.TODO_ITEMS_KEY, onCompleteHandler, _error);
},

_encrypt = function () {
_open(CONST.ENCRYPT);
},

_decrypt = function () {
_open(CONST.DECRYPT);
};

$.subscribe("eoc-open", function (e, action) {
if (action) { // == CONST.ENCRYPT
_write();
} else { // == CONST.DECRYPT
_read();
}
});

Encrypt follows mostly the same steps, except the action after you open the cache will call _write instead of _read. You then run _getData to get the current list, turn it into a string with JSON.stringify, and store it in the cache. Close the cache after every encrypt and decrypt.

Figures 4 and 5 show the finished app running on the iPhone simulator.

Figure 4. The finished application running on the iPhone simulator (Passcode Page)
Figure 4. The finished application running on the iPhone simulator (Passcode Page)
Figure 5. The finished application running on the iPhone simulator (Main Page)
Figure 5. The finished application running on the iPhone simulator (Main Page)

Conclusion

Part 2 of this introductory series on IBM Worklight continued to leverage the Worklight development environment setup in Part 1 and add functionality to build the Todo sample application. Along the way, you learned how structuring your code can benefit development, presentation, and maintenance of your application. You also learned about persisting the data (task list) on your device by leveraging Worklight’s Encrypted Offline Cache functionality. The conclusion to this series will add server-side connectivity with adapters to complete the sample application.


Download

DescriptionNameSize
Sample application project filestodo-app-part2.zip18.5MB

Resources

Learn

Get products and technologies

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Mobile development on developerWorks


  • Bluemix Developers Community

    Get samples, articles, product docs, and community resources to help build, deploy, and manage your cloud apps.

  • Mobile weekly

    Innovations in tools and technologies for mobile development.

  • DevOps Services

    Software development in the cloud. Register today to create a project.

  • IBM evaluation software

    Evaluate IBM software and solutions, and transform challenges into opportunities.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Mobile development, WebSphere,
ArticleID=827472
ArticleTitle=Working with Worklight, Part 2: Developing structured modules and using the Encrypted Offline Cache feature in IBM Worklight
publish-date=07252012