Introduction

PhoneGap is an HTML5 app platform that allows you to author native applications with web technologies and get access to APIs and app stores. PhoneGap leverages web technologies developers already know best... HTML and JavaScript. Starting with OpenMobster 2.2-M8, you can write offline web apps with synchronization of data using the OpenMobster Sync Plugin for PhoneGap. The Sync Plugin exposes the native Sync service to the JavaScript layer using the PhoneGap bridge technology. The rest of this chapter will discuss how to use the Sync Plugin using a JQuery based sample offline application.


Features

  • two way synchronization between the local sqlite database and the corporate backend in the Cloud
  • Offline mode operation. All data changes are tracked and auto synchronized with the Cloud once the connection returns
  • Use of Push notifications to push data changes from the Cloud to the device
  • Support for replicating changes to multiple devices like iCloud does
  • A Java based Channel Framework for integrating your backend with the Cloud

System Requirements


Running the Cloud Server

cd PhoneGap/plugin-jquery-cloud

mvn
-PrunCloud integration-test

This should make the OpenMobster Cloud Server up and running for the Offline App.

Cloud Activation

For security reasons, before apps can use the OpenMobster Cloud, the device must be registered with the cloud. This is done using a CloudManager App that comes with the OpenMobster distribution.

You can locate this App in the distribution under Android/core-runtime/CloudManager.apk. You can install this App on the Android device or emulator using the following command:

adb install -r CloudManager.apk

Once installed you can use the Activate function to register with the Cloud.

Installing the Offline App

adb install -r JQueryOfflineApp.apk

Dissecting the JQuery Offline App

Load Synchronized Beans

//read the oids of the tickets stored in the sync channel
                        window
.plugins.sync.readall(channel,
                               
function(oids)
                               
{
                                       
if(oids =='0')
                                       
{
                                               
return;
                                       
}
                                       
                                        oids
= JSON.parse(oids);
                                       
var length = oids.length;
                                       
for(var i=0; i<length; i++)
                                       
{
                                           
var oid = oids[i];
                                           
                                           
//read the value of the 'title' property of the synchronized bean
                                           window
.plugins.sync.value(channel,oid,'title',
                                                   
function(value)
                                                   
{
                                                               
var encodedOid = encodeURIComponent(oid);
                               
                                                               
//create a list item corresponding to the ticket in question
                                                                html
+='<li><a href="#read_ticket?oid='+encodedOid+'" data-rel="dialog">'+value+'</a></li>';
                                                   
},
                                                   
function(error)
                                                   
{
                                                   
}
                                           
);
                                       
}
                               
},
                               
function(error)
                               
{
                                        alert
('Sync Plugin:'+error);
                               
}
                       
);

This function reads the oids of the beans and then iterates through each bean and extracts the title property.

window.plugins.sync.readall(channel,
                               
function(oids)
                               
{
                                       
if(oids =='0')
                                       
{
                                               
return;
                                       
}
                                       
                                        oids
= JSON.parse(oids);

Invokes the readall function and reads the oids of all the beans stored in the sync channel. If the function is successful it returns an array of oids in JSON format. oids are then parse into a JavaScript object using the JSON.parse function.

//read the value of the 'title' property of the synchronized bean
                                           window
.plugins.sync.value(channel,oid,'title',
                                                   
function(value)
                                                   
{
                                                               
var encodedOid = encodeURIComponent(oid);
                               
                                                               
//create a list item corresponding to the ticket in question
                                                                html
+='<li><a href="#read_ticket?oid='+encodedOid+'" data-rel="dialog">'+value+'</a></li>';
                                                   
},
                                                   
function(error)
                                                   
{
                                                   
}
                                           
);

window.plugins.sync.value reads the value of the specified title property. It takes the channel name and the oid of the bean as arguments to locate the bean whose property is to be read.

Add a New Bean to the Sync Channel

window.plugins.sync.addNewBean(channel,
                                       
function(tempoid)
                                       
{
                                                window
.plugins.sync.updateBean(channel,tempoid,'title',title,
                                               
function(success)
                                               
{
                                               
},
                                               
function(error)
                                               
{
                                               
});
                                               
                                                window
.plugins.sync.updateBean(channel,tempoid,'customer',customer,
                                               
function(success)
                                               
{
                                               
},
                                               
function(error)
                                               
{
                                               
});
                                               
                                                window
.plugins.sync.updateBean(channel,tempoid,'specialist',specialist,
                                               
function(success)
                                               
{
                                               
},
                                               
function(error)
                                               
{
                                               
});
                                               
                                                window
.plugins.sync.updateBean(channel,tempoid,'comments',comments,
                                               
function(success)
                                               
{
                                               
},
                                               
function(error)
                                               
{
                                               
});
                                       
},
                                       
function(error)
                                       
{
                                                alert
("Sync Plugin:"+error);
                                       
});
                                       
                                       
//Commit here
                                        window
.plugins.sync.commit(function(success)
                                       
{
                                                alert
("Ticket was successfully added");
                                       
},
                                       
function(error){
                                                alert
("Ticket Add Error:"+error);
                                       
});

The above code creates a new bean in the Sync Channel. Once the bean is created, its properties are updated and committed to the Sync Engine for synchronization

window.plugins.sync.addNewBean(channel,
                                       
function(tempoid)
                                       
{

window.plugins.sync.addNewBean creates a new bean into the Sync Channel. The method returns a temporary oid used to refer to this newly added bean.

window.plugins.sync.updateBean(channel,tempoid,'title',title,
                                               
function(success)
                                               
{
                                               
},
                                               
function(error)
                                               
{
                                               
});
                                               
                                                window
.plugins.sync.updateBean(channel,tempoid,'customer',customer,
                                               
function(success)
                                               
{
                                               
},
                                               
function(error)
                                               
{
                                               
});

window.plugins.sync.updateBean updates the specified property on the bean referred to by its oid. In this case it modifies the title property on the newly added bean referred to by tempoid.

//Commit here
                                        window
.plugins.sync.commit(function(success)
                                       
{
                                                alert
("Ticket was successfully added");
                                       
},
                                       
function(error){
                                                alert
("Ticket Add Error:"+error);
                                       
});

window.plugins.sync.commit commits the beans into the Sync Channel for synchronization

Updating an existing Bean in the Sync Channel

var oid = $('#update_ticket_oid').val();
                                       
                                       
//update the 'title' property on the ticket bean
                                        window
.plugins.sync.updateBean(channel,oid,'title',title,
                                       
function(success)
                                       
{
                                               
                                       
},
                                       
function(error)
                                       
{
                                       
});
                                       
                                       
//update the 'customer' property on the ticket bean
                                        window
.plugins.sync.updateBean(channel,oid,'customer',customer,
                                       
function(success)
                                       
{
                                               
                                       
},
                                       
function(error)
                                       
{
                                       
});
                                       
                                       
//update the 'specialist' property on the ticket bean
                                        window
.plugins.sync.updateBean(channel,oid,'specialist',specialist,
                                       
function(success)
                                       
{
                                               
                                       
},
                                       
function(error)
                                       
{
                                       
});
                                       
                                       
//update the 'comments' property on the ticket bean
                                        window
.plugins.sync.updateBean(channel,oid,'comments',comments,
                                       
function(success)
                                       
{
                                               
                                       
},
                                       
function(error)
                                       
{
                                       
});
                                       
                                       
//commit
                                    window
.plugins.sync.commit(function(success)
                                       
{
                                                alert
("The Ticket was successfully saved");
                                       
},
                                       
function(error){
                                                alert
('Ticket Update Failed: '+error);
                                       
});

This is very similar to the add new bean explanation above. It updates each property of the bean and then calls commit to get the bean synchronized with the Cloud.

Delete a Bean from the Sync Channel

function deleteTicket()
                               
{
                                       
var oid = $('#read_ticket_oid').val();
                                       
                                       
//delete this bean
                                        window
.plugins.sync.deleteBean(channel,oid,
                                               
function(success)
                                               
{
                                                       
//commit
                                                    window
.plugins.sync.commit(function(success)
                                                       
{
                                                                alert
("The Ticket was successfully deleted");
                                                       
},
                                                       
function(error){alert("Ticket Delete Failed: "+error);});
                                               
},
                                               
function(error)
                                               
{
                                                        alert
("Ticket Delete Failed: "+error);
                                               
}
                                       
);
                                        $
.mobile.changePage('#tickets','slide',true,false);
                               
}

window.plugins.sync.deleteBean deletes the bean referred to by the oid on the specified channel.

window.plugins.sync.commit commits this change into the Sync Channel and prepares for synchronization with the Cloud.


Dissecting the Cloud

The MobileBean

publicclassJQueryBeanimplementsMobileBean,Serializable
                                       
{
                                               
@MobileBeanId
                                               
privateString oid;

Creates a MobileBean by implementing the MobileBean interface. This is the component which will be injected into the Sync Channel. It will then be accesssed on the device via the Sync Plugin API. The MobileBeanId annotation specified that the oid field will serve as the unique object identifier for these beans.

Full Source for the MobileBean implementation:

publicclassJQueryBeanimplementsMobileBean,Serializable
{
       
@MobileBeanId
       
privateString oid;
       
       
privateString title;
       
privateString customer;
       
privateString specialist;
       
privateString comments;
       
       
publicJQueryBean()
       
{
               
       
}

       
publicString getOid()
       
{
               
return oid;
       
}

       
publicvoid setOid(String oid)
       
{
               
this.oid = oid;
       
}

       
publicString getTitle()
       
{
               
return title;
       
}

       
publicvoid setTitle(String title)
       
{
               
this.title = title;
       
}

       
publicString getCustomer()
       
{
               
return customer;
       
}

       
publicvoid setCustomer(String customer)
       
{
               
this.customer = customer;
       
}

       
publicString getSpecialist()
       
{
               
return specialist;
       
}

       
publicvoid setSpecialist(String specialist)
       
{
               
this.specialist = specialist;
       
}

       
publicString getComments()
       
{
               
return comments;
       
}

       
publicvoid setComments(String comments)
       
{
               
this.comments = comments;
       
}
}

The Channel

The Channel is the component that exposes the MobileBeans to the Sync Engine via a CRUD (Create, Read, Update, Delete) interface.

@ChannelInfo(uri="plugin_jquery_channel", mobileBeanClass="org.openmobster.core.phonegap.plugin.jquery.cloud.JQueryBean")
publicclassPluginJQueryChannelimplementsChannel

The ChannelInfo.uri specifies the name of the Sync Channel and ChannelInfo.mobileBeanClass specifies the class of the MobileBean instance that the channel will be dealing with. The MobileBean instances used by the Channel implementation must be instances of this specified class. If this rule is not followed there will be unexpected errors during the synchronization process.

Read the MobileBeans
        @Override
       
publicList<?extendsMobileBean> readAll()
       
{
               
Collection<Object> all =this.objectStore.readAll();
               
List<JQueryBean> beans =newArrayList<JQueryBean>();
               
if(all !=null&&!all.isEmpty())
               
{
                       
for(Object bean:all)
                       
{
                                beans
.add((JQueryBean)bean);
                       
}
               
}
               
               
return beans;
       
}

       
@Override
       
publicList<?extendsMobileBean> bootup()
       
{
               
returnthis.readAll();
       
}
       
       
@Override
       
publicMobileBean read(String id)
       
{
               
return(JQueryBean)this.objectStore.read(id);
       
}                                              
Create the MobileBean
@Override
       
publicString create(MobileBean mobileBean)
       
{
               
JQueryBean toCreate =(JQueryBean)mobileBean;
               
returnthis.objectStore.save(toCreate.getOid(), toCreate);
       
}
Update the MobileBean
@Override
       
publicvoid update(MobileBean mobileBean)
       
{
               
JQueryBean toUpdate =(JQueryBean)mobileBean;
               
this.objectStore.save(toUpdate.getOid(), toUpdate);
       
}
Delete the MobileBean
@Override
       
publicvoiddelete(MobileBean mobileBean)
       
{      
               
JQueryBean toDelete =(JQueryBean)mobileBean;
               
this.objectStore.delete(toDelete.getOid());
       
}

Conclusion

This tutorial should give you a good idea on how to develop Offline Sync Apps using PhoneGap and the OpenMobster Sync Plugin. For more info about the Plugin please take a look at the API Reference document