Building an App Using the Personal Cloud Application Architecture


Summary

The personal cloud application architecture is a post-Web 2.0 programming model that separates users data from application logic and application data. This post explains how to build PCAA-style applications by converting a simple, JavaScript-based TODO list application into one that stores user data in the user's personal cloud.

TODO icon

Last week, I released a white paper that introduced the personal cloud application architecture (PCAA). A PCAA is a post-Web 2.0 architecture.

The traditional Web 2.0 application architecture looks like this with the database in the back of a front-end that provides UI and business logic functions:

standard_web_architecture

A PCAA is more modular, allowing the data (and other standard functions like inter-cloud subscriptions and notifications) to be separated from the application like so:

unhosted_web_architecture

This post shows how to build a PCAA-style application that conforms to the model shown above. The data and other critical functions are stored in the user's personal cloud and the application itself is hosted on a separate Web site.

I have built a simple, JavaScript-based TODO list application. If you play around with it for a minute, you'll see how it works. You can add and delete items. The problem is that there's no persistence layer, so reloading the page reinitializes the application.

In the remainder of this post, I'll show you how to use a personal cloud running CloudOS to add persistence to the TODO application (you can see the code for the TODO application on Github). There are five main changes we have to make:

  1. Load and configure the CloudOS.js library
  2. Add the capability to link the application to a personal cloud using OAuth
  3. Initialize the application when it loads by getting any TODO items from the cloud and displaying them
  4. Store new TODO items in the cloud
  5. Remove deleted TODO items from the cloud

We'll cover each of these in turn.

Configuration

Configuring the applicaition to use the CloudOS.js library is straightforward. First we add the <script/> tag to load the library.

<script type="text/javascript" 
        src="http://todo.windley.com/js/CloudOS.js"></script>

We need to initialize the library with the application keys and callback URL. We add these lines to the top of the <script/> element with the TODO list code:

CloudOS.appKey = "0AB2F236-B1DE-11E2-B9AC-D788FE2E5C38";
CloudOS.callbackURL = "http://todo.windley.com/linkable.html";

We got the key by registering the TODO app in the Kynetx Developer Kit (KDK) application inside SquareTag. (Instructions for doing this are in the README for the CloudOS.js library.) When we registered the app, we also registered the callback URL. Because of the way this particular OAuth flow works, you have to register your application with every personal cloud hosting provider that you want it to work with. If you use more than one personal cloud hosting service, you would chose the app key based on the provider the user has chosen rather than hardcoding as I've done above.

Linking

The most complex change is modifying the TODO application so it can link to the personal cloud since we have to handle the UI components that allow linking and unlinking the cloud.

The first step is to add the "login" and "logout" buttons to the menu bar (the TODO app uses Twitter Bootstrap):

<ul class="nav pull-right">
  <li class="nav-item nav-auth" style="display:none;">
    <a href="#" id="nav-logout">Logout</a></li>
  <li class="nav-item nav-anon" style="display:none;">
    <a href="#" class="oauth-sqtag-url">Login</a></li>
</ul>

Notice that they're both hidden by default.

Next we need to wire the buttons up. The "login" button gets a standard HTML link since it has to take the user off to their personal cloud for authentication. The "logout" button gets a click handler. The real work in the logout click handler is done by CloudOS.removeSession();, the library call for deleting the session. It also shows the login button and clears the TODO list.

var OAuth_Sqtag_URL = CloudOS.getOAuthURL();
$('a.oauth-sqtag-url').attr('href', OAuth_Sqtag_URL);


$('#nav-logout').click( function() {
    CloudOS.removeSession();
    $('li.nav-auth').hide();
    $('li.nav-anon').show();
    $('div.todo_list').html('');
    return false;
});

Besides wiring up the buttons, we need to do the real work of getting the current session if the app is already linked to a personal cloud and responding to the callback from the personal cloud as part of the OAuth flow.

CloudOS.retrieveSession();

if (CloudOS.authenticatedSession()) {
  $('li.nav-auth').show();
  $('li.nav-anon').hide();
} else {
  $('li.nav-auth').hide();
  $('li.nav-anon').show();
  CloudOS.getOAuthAccessToken(
   CloudOS.retrieveOAuthCode(window.location.search.substring(1)),
   function(json) {
     window.location.href = window.location.href.split('?')[0];
   });
}

If we're already in an authenticated session, then we just show the right button. Otherwise, we have to get an access token from the personal cloud using the code that the OAuth server sends back. Note that we're using a single URL for the entire app, including handling the OAuth callback, so after we get the OAuth access token, we reload the page using the base URL. A more complicated application would have a specific flow for handling the OAuth callback.

Initialization

We initialize the TODO list by showing the current TODO items. CloudOS provides a way to retrieve items in a given namespace. We've chosen the todo namespace for this demonstration. Technically, we shouldn't use a bare namespace (without a unique ID) to store things in the user's PDS unless it is a standard schema. This avoids applications overwriting each other's data. While there is not standard todo schema at present, we anticipate creating one.

Using the CloudOS.PDSList() function, we retrieve everything from the PDS in the todo namespace and loop over them (using the jQuery.each() operator) calling the helper function add_todo_list_item() that was already part of the application's JavaScript:

CloudOS.PDSList ('todo', function(json){
    $.each(json || [], function(id, desc) {
       add_todo_list_item(id, JSON.parse(desc))
    });
});		    

This places each TODO item in the PDS in the list.

Adding

When the user types in a new TODO item and clicks "Add", there is a click handler in the application JavaScript that uses the add_todo_list_item() to put the new item in the list. The following shows the click handler with the new code in red:

$('#add_todo').click( function() {
  var todoDescription = $('#todo_description').val();
  var todo_id = 'todo/'+now();
  // ---- add todo to PDS ---
  CloudOS.PDSAdd ('todo', todo_id, todoDescription, function(){
    console.log("Added " + todo_id + " as " + todoDescription);
  });
  add_todo_list_item(todo_id, todoDescription);
  $('#todo_form')[0].reset();
  return false;
});  

The CloudOS.PDSAdd() function adds new items to the todo namespace in the user's PDS using the application's ID and description as the key and value. We're logging the return for debugging purposes.

Deleting

Deleting items is much the same. There is a click handler for handling delete requests. The only thing that makes it more complicated is that more than one thing can be deleted at a time.

$('#del_todo').click( function() {
  $('input:checked').map(function() {
    var todo_id = $(this).val();
    // ---- del todo from PDS ---
    CloudOS.PDSDelete ('todo', todo_id, function(){
      console.log("Deleted " + todo_id);
    });
    return $(this).parent().parent().remove();
  })
  return false;
});

Note that all of the CloudOS.js functions allow callbacks. This is important because the calls to the CloudOS are made asynchronously. If you need to do something with the data, you have to process it in the callback function which is only called once the asynchronous call has returned. For example, in the initialization above, we want to show the results of the CloudOS.PDSList() function, so we do that in the callback function. For adding and deleting, there's nothing to do, so we merely log the result for debugging purposes.

Going Further

You can try the TODO list application yourself by clicking the login button and signing into SquareTag. Create an account if you need one: they're free.

The TODO application uses only the personal data services (PDS) of CloudOS. PDS is arguably the simplest part of CloudOS. CloudOS also provides notification and cloud-to-cloud subscription services. The Forever application uses this same PCAA architecture but makes use of notifications and subscriptions as well. I encourage you to play with Forever to familiarize yourself with it's operation (go ahead and send an invitation to me at pjw+forever@kynetx.com). You should also read Personal Cloud Application Architecture white paper to understand more details. The code for Forever is available on Github if you'd like to study it.

The TODO list application and Forever both make use of the CloudOS.js library to speak to personal clouds based on CloudOS. You can gain a better understanding of the kinds of functionality available in CloudOS by reading the README file for CloudOS.js. The CloudOS.js library, however only captures the built-in portions of CloudOS (and frankly only those we've needed to date). The CloudOS API is extensible by developers using KRL rulesets.

The PCAA is a variant on the architecture that is being promoted by unhosted web apps and remotestorage. PCAA goes beyond that model by offering a richer API that includes not just storage, but other services that developers might need. For example, Forever makes use of cloud-to-cloud subscriptions and those doesn't need to keep track of or manage connections as well as make notification to the user and between the user and her connections. Without CloudOS, a developers would have to build all of that functionality themselves. For more information, see the PCAA white paper.

Note that while I've built the demo in this post as an unhosted application with no server side at all, that's not required. Hybrid models that store application data in a database and user data in a personal cloud also work, as do mobile applications.