You are on page 1of 90

OpenMobster - Mobile Cloud Platform

App Developer Guide


openmobster at gmail.com

OpenMobster - Mobile Cloud Platform: App Developer Guide


openmobster at gmail.com
2.2-SNAPSHOT

Table of Contents
1. Introduction to OpenMobster - Mobile Cloud Platform .......................................................... 1
Data Synchronization .................................................................................................. 1
Real-Time Push Notifications ....................................................................................... 1
Mobile RPC (Remote Procedure Call) ............................................................................ 1
Management Console .................................................................................................. 1
2. Mobile Programmer's Dilemma ......................................................................................... 2
............................................................................................................................... 2
WebApp ("Browser based") Development ....................................................................... 2
Advantages ........................................................................................................ 2
Disadvantages .................................................................................................... 2
App ("Native") Development ........................................................................................ 3
Advantages ........................................................................................................ 3
Disadvantages .................................................................................................... 3
Popular Mobile Platforms (in no particular order of preference or market share) ..................... 3
Blackberry ......................................................................................................... 3
Google Android ................................................................................................. 3
iPhone .............................................................................................................. 3
Symbian ............................................................................................................ 4
Windows Mobile ................................................................................................ 4
............................................................................................................................... 4
Back to the Future ...................................................................................................... 4
3. Programming Concepts .................................................................................................... 5
Cloud Server ............................................................................................................. 5
Channel ............................................................................................................ 5
MobileServiceBean ............................................................................................. 5
Mobile App Frameworks ............................................................................................. 5
Mobile Data Framework ...................................................................................... 5
Mobile MVC Framework ..................................................................................... 6
Mobile Cloud .................................................................................................... 6
4. Architecture ................................................................................................................... 7
OpenMobster Architecture ........................................................................................... 7
Mobile Cloud Stack .................................................................................................... 8
Sync ................................................................................................................. 8
Push ................................................................................................................. 8
OfflineApp ........................................................................................................ 8
Mobile RPC ...................................................................................................... 9
Network ............................................................................................................ 9
Database ........................................................................................................... 9
Inter-App Bus .................................................................................................... 9
Cloud Server Stack ................................................................................................... 10
5. Get Started: Hello Mobster ............................................................................................. 12
.............................................................................................................................. 12
System Requirements ........................................................................................ 12
Create your first Mobile Cloud App ............................................................................. 12
Developing the Channel ............................................................................................. 12
Step 1: Write the HelloSyncBean ......................................................................... 12
Step 2: Write the HelloSyncChannel .................................................................... 13
Step 3: Configuration ........................................................................................ 15
Developing the Android App ...................................................................................... 16
Step 1: Write the HomeScreen ............................................................................ 16
Step 2: Configuration ........................................................................................ 16

iii

OpenMobster - Mobile
Cloud Platform
Running the App ...................................................................................................... 17
6. Production Mode Installation ........................................................................................... 18
Cloud-Side: Installation .............................................................................................. 18
Install Cloud Server .......................................................................................... 18
Device-Side: Installation ............................................................................................ 18
Android Installation ........................................................................................... 18
7. Sync App Development .................................................................................................. 20
.............................................................................................................................. 20
Tutorial ................................................................................................................... 20
Cloud-Side: Channel Development ....................................................................... 20
App/Device-Side: MobileBean component ............................................................. 24
8. MobileBean .................................................................................................................. 26
MobileBean ............................................................................................................. 26
Cloud-Side ............................................................................................................... 26
Specification .................................................................................................... 26
Device-Side ............................................................................................................. 26
Accessing a Simple Property .............................................................................. 26
Accessing a Nested Property ............................................................................... 26
Accessing an Indexed Property (One-Dimensional Array or a java.util.List) ................. 27
Iterating through an Indexed Property (One-Dimensional Array or a java.util.List) ......... 27
9. Push Programming ........................................................................................................ 28
Sending a Push Notification ........................................................................................ 28
Push Setup on an Android App ................................................................................... 28
Push Setup on an iOS App ......................................................................................... 29
Apple Provisioning ........................................................................................... 29
OpenMobster Provisioning ................................................................................. 29
10. iOS + OpenMobster integration ...................................................................................... 32
Introduction ............................................................................................................. 32
Prepare the mobilecloudlib static library ....................................................................... 32
Start a View-based App ............................................................................................. 32
Create a Group called OpenMobster ............................................................................. 32
Add the libraries and Frameworks ............................................................................... 32
Add OpenMobster bootstrap code ................................................................................ 33
The bootstrapping functions ................................................................................ 33
Integrating the bootstrapping function with the App Delegate .................................... 34
Integrating the CloudManager ..................................................................................... 36
Integrate the CloudManager button on the View ..................................................... 36
Implement the action behind the button ................................................................ 37
Sample App ............................................................................................................. 37
11. iOS + OpenMobster Sample App ................................................................................... 38
Introduction ............................................................................................................. 38
Prepare the mobilecloudlib static library ....................................................................... 38
Run the Cloud Server ................................................................................................ 38
Run the SampleApp .................................................................................................. 38
12. Device-To-Device Push Framework ................................................................................ 39
Introduction ............................................................................................................. 39
Integration ............................................................................................................... 39
Step 1: Extend org.openmobster.android.api.d2d.D2DActivity ................................... 39
Step 2: Configuration ........................................................................................ 40
Step 3: Sample App .......................................................................................... 40
13. PhoneGap: Offline Web Apps using the Sync Plugin ......................................................... 41
Introduction ............................................................................................................. 41
Offline App Usage .................................................................................................... 41
Running the Cloud Server .................................................................................. 41

iv

OpenMobster - Mobile
Cloud Platform

14.

15.

16.

17.

18.

Cloud Activation .............................................................................................. 41


Installing the Offline App .................................................................................. 41
Dissecting the JQuery Offline App .............................................................................. 42
Load Synchronized Beans .................................................................................. 42
Add a New Bean to the Sync Channel .................................................................. 43
Update an existing Bean in the Sync Channel ........................................................ 45
Delete a Bean from the Sync Channel .................................................................. 46
Dissecting the Cloud ................................................................................................. 47
The MobileBean ............................................................................................... 47
The Channel .................................................................................................... 49
PhoneGap + iOS + OpenMobster integration .................................................................... 51
Introduction ............................................................................................................. 51
Prepare the mobilecloudlib static library ....................................................................... 51
Start a Cordova-based App ......................................................................................... 51
Copy JSON components to the App ............................................................................. 51
Create a Group called OpenMobster ............................................................................. 51
Add the libraries and Frameworks ............................................................................... 51
Add OpenMobster bootstrap code ................................................................................ 52
The bootstrapping functions ................................................................................ 52
Integrating the bootstrapping function with the App Delegate .................................... 53
PhoneGapSync App .................................................................................................. 55
PhoneGap: Sync Plugin Reference .................................................................................. 56
Introduction ............................................................................................................. 56
ReadAll - window.plugins.sync.readall ......................................................................... 56
Get a Property Value - window.plugins.sync.value .......................................................... 57
Execute Query Match All - window.plugins.sync.queryByMatchAll ................................... 57
Execute Query Match Atleast One - window.plugins.sync.queryByMatchOne ....................... 58
Execute Query Do Not Match All - window.plugins.sync.queryByNotMatchAll .................... 59
Execute Query Do Not Match Even One - window.plugins.sync.queryByNotMatchOne .......... 59
Execute Query Match Contains All - window.plugins.sync.queryByContainsAll ................... 60
Execute Query Match Contains Atleast One - window.plugins.sync.queryByContainsOne....... 61
Add a New Bean into the Sync Channel - window.plugins.sync.addNewBean ....................... 62
Update a Bean in the Sync Channel - window.plugins.sync.updateBean .............................. 63
Delete a Bean from the Sync Channel - window.plugins.sync.deleteBean ............................. 64
Commit the operations with the Sync Channel - window.plugins.sync.commit ...................... 65
Get the Length of an Array/List property - window.plugins.sync.arrayLength ....................... 65
Insert an object into an Array/List property - window.plugins.sync.insertIntoArray ................ 66
Clear the entries inside an Array/List property - window.plugins.sync.clearArray .................. 67
Location Aware Apps ................................................................................................... 68
Location Aware Apps ................................................................................................ 68
LocationServiceBean ................................................................................................. 68
The App Side Logic .................................................................................................. 69
Processing the Response .................................................................................... 71
Mobile RPC (Remote Procedure Call) Development .......................................................... 72
Cloud-Side: MobileServiceBean implementation ............................................................. 72
Cloud-Side: Configuration .......................................................................................... 73
Cloud-Side: Packaging and Deployment ........................................................................ 73
Putting it altogether ................................................................................................... 73
App/Device-Side: Invoking the MobileServiceBean ........................................................ 73
Management Console ................................................................................................... 74
.............................................................................................................................. 74
GUI Functionality ..................................................................................................... 74
Create Account ................................................................................................. 74
Devices ........................................................................................................... 74

OpenMobster - Mobile
Cloud Platform
Administrators .................................................................................................. 74
Push Setup ...................................................................................................... 74
19. Mobile MVC Framework .............................................................................................. 75
.............................................................................................................................. 75
Components ..................................................................................................... 75
Services .......................................................................................................... 80
Tutorial ........................................................................................................... 80

vi

Chapter 1. Introduction to
OpenMobster - Mobile Cloud Platform
openmobster at gmail.com <openmobster@gmail.com>
OpenMobster is an open source platform for integrating native Mobile Apps with "Cloud" services
It provides the following features:

Data Synchronization
Cloud data is made available to an App's local storage. It is available via a simple API. This allows the App
to function seamlessly in both online as well as offline modes. The data is automatically synchronized with
the Cloud service based on local state changes. These state changes are auto detected and synchronized
with the Cloud. It does not require any special device-side sync-related programming on the part of the
developer.

Real-Time Push Notifications


Changes on the Cloud are automatically pushed to the Apps in real time. The Push mechanism uses pure
network/socket based approach instead of clunky methodologies like sending sms alerts or email alerts.
The Push notifications happen inside the App's execution environment. Push notifications are sent via a
simple API. It does not require the developer to learn any low-level platform specific services.

Mobile RPC (Remote Procedure Call)


Provides a simple way of exposing your server-side coarse grained business services. These services are
invoked via a simple RPC mechanism without any low-level programming like http-client code, client
side REST library, etc on the part of the App developer. There is a simple RPC API that is used for making
these calls.

Management Console
A Management Console is provided to administrate the Cloud Server. It provides security, and account
provisioning features. Over time the console will carry device management features like remote wipe,
remote tracking, remote lock-down, etc.

Chapter 2. Mobile Programmer's


Dilemma
openmobster at gmail.com <openmobster@gmail.com>
The Mobile Platform is a relatively new beast in the world of computer programming. For the longest time
(atleast since 1996 that I know of), companies have tried to come up with ways to squeeze the power of
the Internet into a device that conveniently sits in your pocket. After many stop and go linear approaches,
one company changed the game. Apple with their iPhone release in 2006. A whole new Computer with
different architectural rules, and user expectations was born. The notion of native Apps was created. Even
though "The Browser" is a perfectly mainstream gateway to the Internet on a desktop, the same rule does
not translate naturally to the mobile environment. In fact that was the very reason why Mobile Internet
has been the next big thing atleast for the last 15 yrs. Companies lazily expecting their users to adopt "The
Browser" on the mobile phone without realizing this is a completely different beast. Its a paradigm shift
in computer programming. The Mobile Computer is turning out to be the next step in evolution of the
Personal Computer.

WebApp ("Browser based") Development


Web App Development involves accessing the Mobile App via a native browser located on the device.
Programming can be done using standard web technologies like HTML, CSS, and Javascript>. Just like the
PC world, the App executes completely on the server, while the mobile browser serves as a dumb terminal
rendering just the UI. Some Javascript/Ajax approaches try to add some thickness to the architecture, but
for the most part the App is fully reliant on the server and an active network connection.

Advantages
No need to maintain a different codebase for each native mobile platform.
Write Once, Run Anywhere flexibility for the developer.
No App approval process needed.
Uses the same serverside infrastructure as traditional web applications.

Disadvantages
Not a very good user experience. The network latency on a desktop does not map equally to a mobile
device. Users need information quick. Even a delay of a few milliseconds can result in frustration. Same
pause on a desktop goes completely ignored.
Web apps don't have the native look and feel which makes the user experience un-intuitive. Plus, each
browser renders its content differently depending on the device, which can further add to frustration.
Does not allow access to all the low level services of the mobile platform that can deliver true innovation.
Accessing remote data on the go is not the only real advantage of this new computer. Its ability to
feed context sensitive information back into the system unlocks the potential for a whole new world
of computing.
Some access via javascript and/or browser plugin is available, but it can never replicate the natural feel
of accessing the low level platform API.

Mobile Programmer's Dilemma

Too much dependence on a network connection. No offline access to critical data in the event of a
network outage.

App ("Native") Development


Native App Development involves developing the App using the programming language and APIs
provided by the native platform. It provides the most flexible approach to implementing complicated
functionality and provide the best user experience possible. Here are some of the advantages of developing
a native app.

Advantages
Best user experience with respect to response times and intuitive user interaction
Accessiblity to low level hardware, and sensors to truly take advantage of a mobile computer that is
aware of its surroundings
Offline access to critical data even in the event of network failure
Provide intuitive push based notifications as the state of an App changes remotely

Disadvantages
Managing an App codebase across multiple programming languages and platform APIs
No write once, run everywhere convenience for programmers
Some platforms may require a slightly tedious approval process before installation on an actual device

Popular Mobile Platforms (in no particular


order of preference or market share)
Here is a list of some of the popular smartphone platforms available in the market

Blackberry
Programming Language: Java
Operating System: RIMOS (Proprietary/Open API)

Google Android
Programming Language: Java
Operating System: Android (Open Source, License: Apache 2.0)

iPhone
Programming Language: Objective-C
Operating System: Mac OSX (Proprietary/Open API)

Mobile Programmer's Dilemma

Symbian
Programming Language: C++
Operating System: Symbian (Open Source, License: Eclipse Public License 1.0)

Windows Mobile
Programming Language: C#, .Net Programming Languages
Operating System: Windows Mobile (Proprietary/Open API)
In other words, whether to use the native approach or the web based approach is purely a business decision.
For simple apps that only need to access data via a dumb terminal, native approach is overkill. For complex
apps that fully utilize the power of the underlying platform, a native app is the best route.
The OpenMobster Mobile Cloud Platform aims to deliver the low level infrastructure that provides
services needed to build easy to use, innovative native apps. It takes away the hardwork of writing
middleware infrastructure, so that the app developer can focus their development effort on implementing
their business requirements. Here are some of the ways, OpenMobster tries to alleviate some of the
disadvantages of native app development
The pluggable nature of the Mobile MVC framework makes it easier to port an app across multiple
platforms. Most of the GUI level plumbing is provided by the Mobile Cloud runtime. Only thing
that requires porting are the Screen and Command components that are implemented using the native
programming language/API.
Having a consistent messaging spec across all the device level components. This makes the API features
lot more consistent and only thing that varies across platform code is the syntax of the programming
languge.
Provide the same exact framework API in case where the programming languages are the same. For
instance, Blackberry OS and Google Android are based on the same 'Java' programming language. In
that case the API of the various frameworks have the same exact syntax. This cuts down the porting
effort dramatically. Only code that would require porting is the code that uses the low level platform
API. The code cannot be platform independent, but it can be language-portable.

Back to the Future


The ideal scenario would be to have a standard API/programming language across all platform for native
apps. This is highly impractical considering we still have not achieved this in a desktop environment, and
a mobile computer has many differentiating factors that prevent this from happening.
However, what is possible are native apps that use HTML, and CSS for the GUI presentation layer,
and Javascript for event handling code. This is in fact possible in theory with HTML5. HTML5 aims at
providing a standard for developing cross platform native apps, with all the features and services that are
desirable for a native app. However, this is still an on-going effort at the spec level. HTML5 based native
apps are probably a couple of years away from fruition.

Chapter 3. Programming Concepts


openmobster at gmail.com <openmobster@gmail.com>

Cloud Server
A Cloud Server is the server-side component of the infrastructure that is located in the 'Cloud'. The
system provides mobile-oriented features like data synchronization, real-time push, and mobile rpc. From
an architecture standpoint it sits between the mobile device and the actual cloud data services being
mobilized. The Cloud Server provides a Java based Developer API to expose your data services. Here are
its programming concepts:

Channel
A Channel serves as a gateway for integrating on-device model/data objects with the server-side backend
storage systems such as relational databases, content repositories, or Enterprise systems like CRMs, ERPs
etc. It provides a simple CRUD (Create, Read, Update, and Delete) interface to expose the backend data.
The Channel is specifically designed such that the Developer does not have to worry about any low-level
state management, synchronization, or other mobile-oriented issues. The idea is to keep a Channel a purely
data-oriented component.

MobileServiceBean
A MobileServiceBean exposes some coarse grained business process to the on-device Mobile App.
It provides a very simple request/response based synchronous invocation mechanism. It frees up the
developer from all low-level (Remote Procedure Call) concerns like making network connections, security,
marshalling/unmarshalling payloads etc.
Note: This component is quite simple at the time of the milestone M1 release. Eventually it will provide
more robust REST-based functionality. In any case, the Developer will still be shielded from the low-level
programming details regardless of what higher-level services will be supported.

Mobile App Frameworks


Mobile Data Framework
The Mobile Data Framework provides Cloud data-oriented services like data synchronization, real-time
push notifications, and simple RPC (Remote Procedure Call) mechanism.

MobileBean
MobileBean is a managed Mobile Component which carries the state of the domain object that it represents
on the Cloud. It is propagated from the Cloud Server to the mobile device via its corresponding "Channel"
on the server. The Mobile Data Framework shields the App developer from state management issues like,
offline access, receiving push notifications related to state changes on the server, synchronizing locally
modified beans back with the server, sync concepts like two-way sync, one-way sync etc. The native
runtime smartly tracks the changes to the local state of the MobileBean and decides which type of sync
is needed.

Programming Concepts

MobileService
MobileService facilitates making RPC (Remote Procedure Call) invocations from the device to the server
side 'MobileServiceBean' components. It presents a simple API to the developer and shields them from
low-level networking details, http libraries, REST invocations etc.

Mobile MVC Framework


This is a thick client MVC (Model-View-Controller) framework. It is based on a Rich Internet
Application [http://en.wikipedia.org/wiki/Rich_Internet_application] design principle. At this point in
time of evolution of the mobile space, there isn't a commonly adopted GUI development standard across
various mobile platforms. This results in a lot of App porting activity across platforms. Although this
framework is not designed for (Write Once, Run Anywhere) approach, it abstracts out a lot of the UI
Framework plumbing that would otherwise need to be written, ported and maintained by the developer.
The framework abstracts out some of the low level services into the container such as App bootstrapping,
screen navigation, graceful error handling, and internationalization. There are two types of components
in this framework that use a plugin mechanism and receive call backs to perform activities implemented
using native platform API. These components are:

Screen
Screen is an abstraction for an instance of the App screen that must be made visible to the user at a particular
moment in time The low level Navigation Manager keeps track of the various screens of an App and
provides services such as navigating to a specified screen, going back to the previous screen, and going
to the home screen. Besides the actual implementation of a "Screen" all services related to a "Screen" are
portable across mobile platforms.

Command
Command is an abstraction for an instance of a GUI Event Handler which receives various callbacks based
on the screen's lifecycle A command typically puts a business process into motion via accessing various
other services like the Mobile Cloud Framework components and/or native platform services.
The Mobile MVC Framework is extensible to support various GUI frameworks. This does open the door
for integrating cross platform GUI frameworks like standard widgets, HTML5 based GUI, etc.

Mobile Cloud
Mobile Cloud is an on-device native system service. It hosts the runtime that is used by the above mentioned
App Frameworks. On platforms that support inter-application communication such as Android, there is a
single instance of a Mobile Cloud which is shared by all the Apps installed on the device. This helps make
better use of device resources like storage, network management, push sockets, background services, etc.
On platforms that do not support inter-application communication, an instance of the Mobile Cloud runtime
must be installed by bundling it with each App. The Mobile Cloud also comes with a Cloud Manager
App. The Cloud Manager App provides configuration functions such as secure Device Activation, Push
Management, Channel Management, Discovering/Installing new Apps, etc.

Chapter 4. Architecture
openmobster at gmail.com <openmobster@gmail.com>

OpenMobster Architecture

Architecture

Mobile Cloud Stack

This is a software stack that is installed on the mobile device. It provides the following services to Mobile
Apps: Sync, Push, OfflineApp, Mobile RPC, Network, Database, Inter-App Bus.

Sync
Sync service auto-synchronizes all state changes to App/Moblet Data back with the Cloud Server. It
supports various synchronization modes such as two way sync, one way server sync, one way device sync,
slow sync, and boot sync.

Push
Push service manages state updates being sent as notifications from the Cloud Server. This improves the
mobile user's experience as they do not have to pro-actively check for new information. When relevant
information becomes available on the server, the user is automatically notified via system notifications like
a beep, vibration, etc. Clarification: The Push service is a real time comet based service. The notifications
are received within the context of the App and not as SMS alerts or some other non-intuitive experience.
The experience is just like the Blackberry email experience. The Cloud Server does not require any special
infrastructure like the Blackberry Enterprise Server to make this happen.

OfflineApp
OfflineApp service provided is designed to be an App Developer's best friend. Its carries the management
capabilities to create smart coordination between low-level services like Sync and Push. Because of the

Architecture

OfflineApp service, the programmer never has to write any code to actually perform any synchronization.
Synchronization is something that is managed by the OfflineApp service and it decides which mode of
synchronization is the best for the current runtime state of the App. The App developer is never exposed
to low level synchronization details like two way sync, one way device sync, etc. It coordinates managing
the Push service. It carries the smartness to track the type of data being pushed along with which installed
App on the device needs the notification. The App developer does not have to write any special code to
receive notifications. The moment the data channel for the App is established, all synchronizations and
push notifications are automatically handled by the OfflineApp service.

Mobile RPC
Mobile RPC facilitates making synchronous RPC (Remote Procedure Call) invocations from the device
to the server side 'MobileServiceBean' components.

Network
Network service manages establishing a network connection with the Cloud Server. It manages the
communication channel needed to receive Push notifications from the server. It carries the smartness to
track coverage and establishes proper connections automatically. This is a very low-level service and an
App developer never has to deal with using it directly. The App developer is shielded from any low level
connection establishment, security, protocol details, etc by using the higher level Mobile Data Framework
components.

Database
Database service manages local data storage details for Apps. Depending on the platform in question it
uses the corresponding storage facilities. It is designed to coordinate storage among the suite of Apps/
Moblets installed on the device. It provides thread-safe concurrent access to the Apps. Just like the Network
service, its a low-level service used by the Mobile Data Framework components.

Inter-App Bus
Inter-App Bus service provides low-level coordination/communication between the suite of Apps/Moblets
installed on the device.

Architecture

Cloud Server Stack

This is a software stack that is installed on the server-side. It provides the following services to Mobile
Apps: Sync, Push, Secure Socket-Based Data Service, Mobile RPC, Security, Management Console

Sync
Sync service synchronizes device side App state changes with the backend services where the data actually
originates. It provides a plugin framework to mobilize the backend data. It uses the concept of a data
"Channel" which mobilizes the data in the form of "MobileBean" instances.

Push
Push service monitors data "Channels" for updates. The moment updates are detected, corresponding
Comet-based notifications are sent back to the device. If the device is out of coverage or disconnected for
some reason, it waits in a queue, and delivers the push the moment the device connects back to the network.
Clarification: The push service does not depend on any special infrastructure like a Blackberry Enterprise
Server to achieve its functionality. Its a pure Comet-based approach via a socket channel with the device.

Secure Socket-Based Data Service


Secure Socket-Based Data Service is a high performance socket server based on Java NIO. The service
uses the Apache MINA [http://mina.apache.org/] network application framework. It provides both, a plain
socket server , and a SSL-based socket server, depending on the security requirements of the Apps.

10

Architecture

Mobile RPC
Mobile RPC service on the server-side provides a Remote Procedure Call framework for invoking coarse
grained business services of an App. The components are plugged in as MobileService Beans and the
device-side Mobile RPC service invokes them via a simple synchronous request/response based approach.

Security
Security component provides authentication and authorization services to make sure mobile devices
connecting to the Cloud Server are in fact allowed to access the system. Every device must be first securely
provisioned with the system before it can be used. After the device is registered, it is challenged for proper
credentials when the device itself needs to be activated. Once the device is activated, all Cloud requests
are properly authenticated/authorized going forward.

Management Console
Every instance of a Cloud Server ships with a Command Line application called the Management Console.
The console provides user and device provisioning functionalities. In the future, this same component will
have more device management features like remote data wipe, remote locking, remote tracking, etc.

11

Chapter 5. Get Started: Hello Mobster


openmobster at gmail.com <openmobster@gmail.com>
In the spirit of confidence building when using a new technology, lets start with a simple app. We will
call it the HelloSync app.

System Requirements
Cloud Server
Java SE JDK v6.0

Create your first Mobile Cloud App


Download an OpenMobster distribution from here: Downloads [http://code.google.com/p/openmobster/
downloads/list] .
In your distribution, go to the directory AppCreator. Inside the directory, use a tool called the
'appcreator.bat' (Windows), 'appcreator.sh' (Linux and Mac) to generate a skeleton project

appcreator.bat

This will generate a Maven-based skeleton for the Mobile App. Each generated project has the following
maven modules:
cloud: Contains the src for the Cloud-side Channel component. Java code is located under src/main/
java, and configuration is located under src/main/resources.
app-android: Contains the src for the Android App. Java code is located under src/main/java,
Configuration is located under src/main/resources/moblet-app. Besides the OpenMobster component
setup, the Android SDK specific setup is located under AndroidManifest.xml, and res directory
moblet: This is an assembly component that packages this App into a jar file ready for deployment in
a JBoss AS based OpenMobster instance.

Developing the Channel


Step 1: Write the HelloSyncBean
The HelloSyncBean is a simple annotated MobileBean that carries the domain level information
that will be synchronized with the device. This information is encapsulated inside a MobileBean
instance. It will be used by the native App on the device side. This bean implements the
org.openmobster.server.api.model.MobileBean interface. This is a simple marker interface. It does not
require any methods to be implemented.

package com.hello.sync;

12

Get Started: Hello Mobster

import org.openmobster.cloud.api.sync.MobileBean;
import org.openmobster.cloud.api.sync.MobileBeanId;
public class HelloSyncBean implements MobileBean
{
private static final long serialVersionUID = 1L;
@MobileBeanId
private String oid;
private String message;
public HelloSyncBean()
{
}
public String getOid()
{
return oid;
}
public void setOid(String oid)
{
this.oid = oid;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
}

Step 2: Write the HelloSyncChannel


A Channel serves as a gateway for integrating on-device model/data objects with the server-side backend
storage systems such as relational databases, email servers, content repositories, or Enterprise systems like
CRMs, ERPs etc. It provides a simple CRUD (Create, Read, Update, and Delete) interface to expose the
backend data. The Channel is specifically designed such that the Developer does not have to worry about
any low-level state management, and synchronization issues.
For sake of simplicity, we will only
org.openmobster.server.api.model.Channel interface.

implement

small

portion

of

the

Implement the org.openmobster.server.api.model.Channel interface

13

Get Started: Hello Mobster

package com.hello.sync;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import org.openmobster.cloud.api.sync.Channel;
import org.openmobster.cloud.api.sync.ChannelInfo;
import org.openmobster.cloud.api.sync.MobileBean;
import org.openmobster.core.security.device.Device;
@ChannelInfo(uri="hellosync", mobileBeanClass="com.hello.sync.HelloSyncBean")
public class HelloSyncChannel implements Channel

Annotate the channel class with org.openmobster.server.api.model.ChannelInfo annotation.


uri: Unique value for registering the channel with the Channel Framework.
mobileBeanClass: Class of the MobileBean that will be managed via this channel.

Implement bootup method


@Override
public List<? extends MobileBean> bootup()
{
List<HelloSyncBean> bootupBeans = new ArrayList<HelloSyncBean>();
//Just using mock data...Usually this will extract the information from a backend
for(int i=0; i<5; i++)
{
HelloSyncBean syncBean = new HelloSyncBean();
syncBean.setOid(""+i);
syncBean.setMessage("hello from "+syncBean.getOid());
bootupBeans.add(syncBean);
}
return bootupBeans;
}

This method only returns the essential beans needed to make the App functional. It can be thought of as
providing enough information for booting up the App. The rest of the beans are synchronized silently in
the background without requiring any manual intervention or docking the device to a desktop, etc. This
allows instant usage of the App without having to wait a few hours for all the required data to be loaded.

Implement scanForNew method


@Override

14

Get Started: Hello Mobster

public String[] scanForNew(Device device, Date lastScanTimestamp)


{
//In this example, it pushes something every scan..Just for push demo
return new String[]{"push:1",
"push:2"};
}

This method checks with the backend service if a new MobileBean instance has been created on the
backend connected to by the channel. Based on that it would send the just new bean ids back, or return
null, if nothing new is available. If something new is available, this information is automatically synced
and notified on the user's mobile device. If not, nothing happens on the device side.
device: provides the context around which device should this call apply to. Backend information is
linked via the user identity associated with the device
lastScanTimestamp: provides when the last scan occurred. This way developer knows to only include
beans that may have been created in the backend since this period in time.

Implement read method


@Override
public MobileBean read(String id)
{
//Just mock data....Usually the bean
//would be constructed using the data
//from a backend service or database
HelloSyncBean syncBean = new HelloSyncBean();
syncBean.setOid(id);
syncBean.setMessage("hello from "+syncBean.getOid());
return syncBean;
}

This method provides a fully loaded MobileBean instance associated with the supplied id.

Step 3: Configuration
Register this channel using the cloud/src/resources/META-INF/openmobster-config.xml file.

<?xml version="1.0" encoding="UTF-8"?>


<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="hellosync" class="com.hello.sync.HelloSyncChannel">
<depends>services://MobileObjectMonitor</depends>
<depends>services://MobileServiceMonitor</depends>
</bean>
</deployment>

15

Get Started: Hello Mobster

Developing the Android App


Step 1: Write the HomeScreen
Using the OpenMobster MVC Framework requires at the very least a very basic understanding of Android
Application Fundamentals [http://developer.android.com/guide/topics/fundamentals.html]. A high level
understanding of the concept of Activities is a bonus. The HomeScreen component represents the main/
home screen that is launched when the Android App is launched. The full src code of the HomeScreen
component can be found here [http://openmobster.googlecode.com/svn/samples/hellosync/app-android/
src/main/java/com/hello/sync/app/HomeScreen.java]. In order to keep the tutorial clean, we will only
highlight the aspect that deals with displaying the HelloSyncBeans that are synchronized between the
Cloud and the device. This is accomplished using the following snippet of code:

@Override
public void postRender()
{
ListActivity listApp = (ListActivity)Registry.getActiveInstance().
getContext();
.............

//Show the List of the "HelloSyncBeans" automatically synced and stored on the dev
//As a developer you only deal with the MobileBean component...
//No low-level sync stuff to worry about
if(MobileBean.isBooted("hellosync"))
{
MobileBean[] helloBeans = MobileBean.readAll("hellosync");
//Preparing the ui with data stored in the beans..in the message field
String[] ui = new String[helloBeans.length];
for(int i=0,size=ui.length;i<size;i++)
{
ui[i] = helloBeans[i].getValue("message");
}
//Showing the data in the list
listApp.setListAdapter(new ArrayAdapter(listApp,
android.R.layout.simple_list_item_1,
ui));
}
............
}

Step 2: Configuration
Configure this App with the on-device OpenMobster runtime using app-android/src/resources/mobletapp/moblet-app.xml

16

Get Started: Hello Mobster

<moblet-app>
<!-- Registers the home/main screen of the app -->
<bootstrap>
<screen>com.hello.sync.app.HomeScreen</screen>
</bootstrap>

<!-- Registers App Commands with the OpenMobster Command Framework. App Command
are fired in response to events generated by user interactions
-->
<commands>
<command id='/hellosync/reset'>com.hello.sync.app.ResetChannel</command>
</commands>
<!-- Registers the Cloud channels used by the App -->
<channels>
<channel>hellosync</channel>
</channels>
</moblet-app>

Android platform specific configuration can be found under: android-app/AndroidManifest.xml, androidapp/res/layout/home.xml, and android-app/res/strings.xml

Running the App


Start the Cloud Server. Under the HelloSync project, go to the cloud directory, and type in:
mvn -PrunCloud integration-test
Start the Android emulator. Here [http://developer.android.com/guide/developing/tools/emulator.html]
are more details about using the Android Emulator
emulator -avd droid
and
ddms
Once the emulator is started and ddms is connected, install the development mode DevCloud
CloudManager App and the HelloSync App. Go to the app-android directory and type in:
mvn -Phot-deploy install
Activate the emulated device with the Cloud Server by launching the DevCloud CloudManager App
and clicking the Activate option.
Launch the HelloSync App.
You can download the entire HelloSync App here: HelloSyncApp [http://openmobster.googlecode.com/
svn/samples/hellosync.zip]

17

Chapter 6. Production Mode


Installation
openmobster at gmail.com <openmobster@gmail.com>

Cloud-Side: Installation
Install Cloud Server
Step 1: Download and install JBoss-5.1.0.GA from here [http://www.jboss.org/jbossas/downloads/]
Step 2: Copy openmobster to the JBoss AS server directory. openmobster is a pre-configured/optimized
instance for the OpenMobster Cloud Server
Step 3: In the case of using MySQL5 as the database, modify openmobster-ds.xml according to your
own MySql5 instance
Step 4: Start the JBoss AS instance with the OpenMobster binary installed using: run -c openmobster
-b "a real IP address"
Note: A real IP address like "192.168.0.1" or something like that is needed for the mobile device to be
able to connect to the server. Even in the case of a simulation environment, the device's browser does
not connect to a loopback address like "localhost" or "127.0.0.1"
Step 5: Verify the Cloud Server installation by typing in: http://{cloudserverIp}:{port}/o

Device-Side: Installation
Mobile Cloud infrastructure runtimes MUST be installed on each device, before the device can integrate
with the "Cloud Server". Think of them as bootstrap binaries.
Each mobile platform will have its corresponding set of artifacts that must be first installed on the device.
The current version consists of Google Android 2.0+ support

Android Installation
If you have a Cloud Server running and accessible from the Internet, you can simply download these
binaries from the built-in browser of the device.
Download the following and follow the instructions provided by the device:
http://{cloudServer IP}:{cloudServer port}/o/android/cloudmanager

Device Activation
Step 1: Launch the 'CloudManager' app.
Step 2: Select the 'Activate' function.
Step 3: Follow the wizard and provide the appropriate values

18

Production Mode Installation

Server : IP Address of the Cloud Server


Email : The user id for this user
Password: The password to be used to secure the account

Installing the Sample Offline App


Using your CloudManager App , install the deployed Apps using the Corporate App Store option

19

Chapter 7. Sync App Development


openmobster at gmail.com <openmobster@gmail.com>
A native Mobile App runs within the constraints of its local runtime. A major advantage of this environment
is access to local storage for data associated with the App. If logic is the nervous system of an App, data
is its life blood. Without the data, an App is lifeless. Local Storage brings an App to life instantaneously.
The closer this data is stored, the faster and better is the performance of the App.
A typical Mobile App has the following data-oriented requirements
Data originates in the Cloud.
App related data is synchronized from the Cloud with the local storage over a network connection.
Any data state changes (add/update/delete) via the App are synchronized with the Cloud.
Any data state changes (add/update/delete) on the Cloud are pushed/synchronized with the device.
This data is available to the mobile App even in the event the Cloud is unavailable.
The OpenMobster Cloud Platform uses a "Channel" component on the Cloud-side and a MobileBean
component on the Device-side to provide the above mentioned offline capabilities to an App

Tutorial
Cloud-Side: Channel Development
A Channel serves as a gateway for integrating on-device model/data objects with the server-side backend
storage systems such as relational databases, content repositories, or Enterprise systems like CRMs, ERPs
etc. It provides a simple CRUD (Create, Read, Update, and Delete) interface to expose the backend data.
The Channel is specifically designed such that the Developer does not have to worry about any low-level
state management, and synchronization issues.

Step 1:
Define a simple MobileBean to represent a data entity being mobilized. This MobileBean should adhere
to the MobileBean specification covered here: Specification

import java.util.List;
import org.openmobster.cloud.api.sync.MobileBean;
import org.openmobster.cloud.api.sync.MobileBeanId;
public class DemoBean implements MobileBean
{
@MobileBeanId
private String beanId;

private String demoString; //used to demonstrate mobilizing a simple property of t

private String[] demoArray; //used to demonstrate mobilizing of an indexed propert

20

Sync App Development

private List<String> demoList; //used to demonstrate mobilizing an indexed propert


public DemoBean()
{
}
public String getBeanId()
{
return beanId;
}
public void setBeanId(String beanId)
{
this.beanId = beanId;
}
public String getDemoString()
{
return demoString;
}
public void setDemoString(String demoString)
{
this.demoString = demoString;
}
public String[] getDemoArray()
{
return demoArray;
}
public void setDemoArray(String[] demoArray)
{
this.demoArray = demoArray;
}
public List<String> getDemoList()
{
return demoList;
}
public void setDemoList(List<String> demoList)
{
this.demoList = demoList;
}
}

Step 2:
Provide a Channel implementation that exposes this MobileBean via a CRUD interface.

@ChannelInfo(uri="/offlineapp/demochannel",

21

Sync App Development

mobileBeanClass="org.openmobster.core.examples.offlineapp.DemoBean")
public class DemoChannel implements Channel

bootup
This method provides a subset of the "MobileBean" instances associated with the said device. They provide
just enough information for an App to be functional. This helps with avoiding very long synchronization
sessions. The other beans are loaded on-demand from there on

public List<? extends MobileBean> bootup()


{
List<MobileBean> list = new ArrayList<MobileBean>();
//Just get only the top 5 beans to bootup the service on device side
//This decision is App-specific
for(int i=0; i<5; i++)
{
DemoBean bean = this.demoRepository.getData().get(""+i);
list.add(bean);
}
return list;
}

readAll
This method provides all the "MobileBean" instances associated with the said device.

public List<? extends MobileBean> readAll()


{
List<MobileBean> list = new ArrayList<MobileBean>();
//Get All the Beans associated with this Channel for this Device
Set<String> beanIds = this.demoRepository.getData().keySet();
for(String beanId: beanIds)
{
list.add(this.demoRepository.getData().get(beanId));
}
return list;
}

read
This method loads the particular "MobileBean" instance in question.

public MobileBean read(String id)


{
return this.demoRepository.getData().get(id);

22

Sync App Development

create
Creates a new instance of a "MobileBean" within the backend data service. This happens when a new
instance is created on the device and synchronized back with the Cloud. It returns the unique id generated
by the server and associated with this bean.

public String create(MobileBean mobileBean)


{
DemoBean newBean = (DemoBean)mobileBean;
//Generate a new unique bean Id. This bean was created on the Device and is being
//synchronized with the backend cloud service
String newBeanId = String.valueOf(this.getDemoRepository().getData().size());
newBean.setBeanId(newBeanId);
this.demoRepository.getData().put(newBeanId, newBean);
return newBeanId;
}

update
Synchronizes the updated state of a bean from the device with the state on the Cloud.

public void update(MobileBean mobileBean)


{
DemoBean updatedBean = (DemoBean)mobileBean;
this.demoRepository.getData().put(updatedBean.getBeanId(), updatedBean);
}

delete
Deletes a bean instance that is user confirmed to be deleted from the device.

public void delete(MobileBean mobileBean)


{
DemoBean deletedBean = (DemoBean)mobileBean;
this.demoRepository.getData().remove(deletedBean.getBeanId());
}

Step 3:
Provide the META-INF/openmobster-config.xml that will deploy the "Channel" into the Cloud Server.

23

Sync App Development

<?xml version="1.0" encoding="UTF-8"?>

<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="/offlineapp/demorepo" class="org.openmobster.core.examples.offlineap

<bean name="/offlineapp/demochannel" class="org.openmobster.core.examples.offlin


<property name="demoRepository"><inject bean="/offlineapp/demorepo"/></propert
</bean>
</deployment>

Step 4:
Package the the above classes and the corresponding META-INF/openmobster-config.xml into a simple
jar file.

Step 5:
Deploy this jar file into the "deploy" directory of your JBoss AS instance

Putting it all together


The end-to-end Channel Example is located at : src/dev-tools/sampleApps/offlineapp/cloud and
AppCreator/sampleApps/offlineapp/cloud

App/Device-Side: MobileBean component


On the device side, this data is accessible via the org.openmobster.android.api.sync.MobileBean
component. The device-side MobileBean is a generic component which exposes a Cloud-side MobileBean
information through a robust interface. Device-side MobileBean component semantic are covered
here:Specification
Here are some simple methods to access a MobileBean on the device
readAll: Returns all MobileBean instances associated with a channel. Chances are some of the instances
are only proxies that will be loaded seamlessly when they are really needed on-demand. This process
happens behind the scenes and there is nothing special a programmer needs to do.

MobileBean[] demoBeans = MobileBean.readAll("/offlineapp/demochannel");


actions = new Vector();
int size = demoBeans.length;
for(int i=0; i<size; i++)
{
if(!demoBeans[i].isProxy())
{
actions.addElement(demoBeans[i].getValue("demoString"));
}
else
{
actions.addElement(demoBeans[i].getId()+": proxyState");
}
}

24

Sync App Development

getValue: Reads the value associated with a field/property of an instance of a bean. A property
expression is provided to access this information.

demoBeans[i].getValue("demoString");

This particular method call reads the "demoString" property of the corresponding Cloud-Side
MobileBean instance covered earlier.
setValue: Updates the field/property of an instance of a bean. A property expression and its value are
provided.

demoBeans[i].setValue("demoString", "new updated value");

For a more detailed coverage of the MobileBean usage, please see some example code located at: src/devtools/sampleApps/offlineapp/app-android and AppCreator/sampleApps/offlineapp/app-android

25

Chapter 8. MobileBean
openmobster at gmail.com <openmobster@gmail.com>

MobileBean
MobileBean is a managed Mobile Component which carries the state of the domain object that it represents
on the server. It is propagated from the Cloud Server to the mobile device via its corresponding Channel
on the server. The Mobile Data Framework shields the App developer from state management issues like,
offline access, receiving push notifications related to state changes on the server, synchronizing locally
modified beans back with the server, etc.
The concept of a MobileBean applies to both sides of the world, Cloud-Side as well as Device-Side.

Cloud-Side
On the Cloud-Side the MobileBean is a simple Java Object that implements the
org.openmobster.cloud.api.sync.MobileBean interface. The MobileBean is processed by
its corresponding Channel. Through the channel instances of these beans are serialized into wire format
and propagated to their respective devices. In order to be successfully serialized/deserialized, they should
follow the proper specification.

Specification
The system successfully processes the following properties of a bean: Simple Property, Nested Property,
One-Dimensional Array property, and Parameterized java.util.List properties of Concrete
Types.
Array PropertiesMUST NOT contain Null elements.
MUST contain an empty constructor
MUST contain provide public get and set methods for each one of its properties

Device-Side
On the Device-Side the MobileBeans from a channel are made accessible via the Mobile Data Framework.
The generic org.openmobster.android.api.sync.MobileBean component is used to extract
the state associated with each instance. It provides various state-oriented operations. The individual
properties of a bean are accessed using simple and intuitive expressions.

Accessing a Simple Property


For a simple property myName on a bean, the following expression is used:
MobileBean.getValue("myName");

Accessing a Nested Property


For a nested property myAddress.myStreet on a bean, the following expression is used:

26

MobileBean

MobileBean.getValue("myAddress.myStreet");

Accessing an Indexed Property (One-Dimensional Array


or a java.util.List)
For an indexed property "myName" on the "third element" of an Array or List named "users" on
a bean, the following expression is used:

MobileBean.getValue("users[2].myName");

Iterating through an Indexed Property (One-Dimensional


Array or a java.util.List)
private void iterateEmails(MobileBean mobileBean)
{
BeanList emails = mobileBean.readList("emails");
for(int index=0; index<emails.size(); index++)
{
BeanListEntry email = emails.getEntryAt(index);
System.out.println(email.getProperty("from"));
System.out.println(email.getProperty("to"));
System.out.println(email.getProperty("subject"));
System.out.println(email.getProperty("message"));
}
}

In the background, the state of all device-side MobileBean instances is tracked by the OfflineApp service.
Any state updates are automatically synchronized back with its Cloud-Side channel using the appropriate
synchronization mode. As far as the App developer is concerned, they just update this state locally and
go about their business.

27

Chapter 9. Push Programming


openmobster at gmail.com <openmobster@gmail.com>

Sending a Push Notification


You can send a push notification from the cloud using the Push API. This API is located on the
org.openmobster.cloud.api.push.PushService object. On this object you use the following method

/**

* A device agnostic Push method. Push is associated with the user and not
*
* @param identity user that must receive this message
* @param appId unique application id this push is associated with
* @param message message to be sent
* @param title title of the message
* @param details any other details associated with the message
*/
public void push(String identity, String appId, String message, String titl

Push Setup on an Android App


You can setup Push Notification support in your app via two configuration files. Before we go into those
details you must understand that there are two types of push notifications. User Initiated Push notification
using the PushService API, and Sync Initiated Push Notification which is generated by the Sync Engine.
Configuration:AndroidManifest.xml

<receiver android:name="org.openmobster.core.mobileCloud.api.ui.framework.push
<intent-filter>
<action android:name="org.crud.android.app"/>
</intent-filter>
</receiver>

<receiver android:name="org.openmobster.core.mobileCloud.api.ui.framework.p
<intent-filter>
<action android:name="org.openmobster.sync.push"/>
</intent-filter>
</receiver>

First you setup the user initiated push notification receiver. In the action value you have to make sure its
the same as the name of the unique package that identifies this application.
Next, you will setup sync initiated push notifications. There is no extra configuration to keep in mind here.

28

Push Programming

openmobster-app.xml

<push>

<launch-activity-class>org.openmobster.core.mobileCloud.android_nat
<icon-name>push</icon-name>
</push>

Here, launch-activity-class indicates the activity that must be launched when the user clicks on the
notification from the notification bar
icon-name points to a drawable image that should be displayed as an icon with the notification.

Push Setup on an iOS App


This is a guide to integrate the iPhone Apple Push Notification (APN) based system with the
OpenMobster? Push Service. It consists of several provisioning steps from the Apple side and integration
via the Management Console on the OpenMobster? Side.

Apple Provisioning
Step 1: Obtain the Application Certificate
In order to push via the APN service, the provider side (OpenMobster?->APN connection) requires
a certificate for each App registered for Push Notifications. The best instructions for doing the
proper provisioning and obtaining a certificate is explained at : http://mobiforge.com/developing/story/
programming-apple-push-notification-services.

Step 2: Getting an aps_production_identity.p12 certificate


Once you have downloaded the aps_production_identity.cer file from the Apple Provisioning Portal
Import the aps_production_identity.cer into the KeyChain?. Double-clicking the file will do it
Select both certificate and private key (associated to the application you wish to use to send notifications)
Right click, and select Export 2 elements, give a name (for example : aps_production_identity.p12) and
password (for example : p@ssw0rd) and then export as p12.

OpenMobster Provisioning
Step 1: Register the App and the Device Token
On the OpenMobster? side, Apps that want Push notifications must be registered with the OpenMobster?
system. The Device Token is also needed to be registered as it is a requirement for the Apple Push
Notification Service. This registration is as follows:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWith


// Override point for customization after application launch.

29

Push Programming

// Add the view controller's view to the window and display.


[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
//Bootstrap the Cloud services
[self startCloudService];
//This registers the App for Push Notifications
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound)];
return YES;
}

If the registation is successful a callback is invoked on the delegate. It goes as follows:

- (void)application:(UIApplication *)app didRegisterForRemoteNotificatio


{

NSString *deviceTokenStr = [NSString stringWithFormat:@"%@",deviceToken];


deviceTokenStr = [StringUtil replaceAll:deviceTokenStr :@"<" :@""];
deviceTokenStr = [StringUtil replaceAll:deviceTokenStr :@">" :@""];
NSLog(@"DeviceToken: %@",deviceTokenStr);
@try
{
SubmitDeviceToken *submit = [SubmitDeviceToken withInit];
[submit submit:deviceTokenStr];
}
@catch (SystemException * syse)
{
UIAlertView *dialog = [[UIAlertView alloc]

initWithTitle:@"Token
message:@"Device Token
delegate:nil
cancelButtonTitle:@"OK
dialog = [dialog autorelease];
[dialog show];
}
}

These two operations registers the Application for Push notifications both on the device and on the
OpenMobster? Push Service.

30

Push Programming

Step 2: Upload the certificate .p12 file


Login to the Management Console: http://cloud-server-address/console
Select Push Setup
Find the App associated with this certificate
Upload the certificate and supply its password
If successfull, the icon next to the App will turn green
Step 3: Send a Test Push
Click on the App
Click the 'Test Push' button
Select the 'Device' where it should be sent
You should receive a Push alert on your phone

31

Chapter 10. iOS + OpenMobster


integration
openmobster at gmail.com <openmobster@gmail.com>

Introduction
As of version 2.2-M1, iOS is fully supported by OpenMobster. Here are some tips related to iOS and
OpenMobster integration

Prepare the mobilecloudlib static library


Open
the
mobilecloudlib
mobilecloudlib.xcodeproj

XCode

project

by

opening:

iPhone/mobilecloudlib/

Build the project in XCode


For some reason, building the mobilecloudlib fail to compile if your XCode code location is set to the
recommended setting of "Derived Data". You must change this option to "Location Specified By Targets".
Please take a look at this thread for details: https://groups.google.com/forum/#!searchin/openmobsterusers/mobilecloudlib/openmobster-users/zJhJKbFekLs/WiNWtKfG_RcJ

Start a View-based App


Go to File>New Project. In the displayed project templates select the View-based Application and
follow the wizard

Create a Group called OpenMobster


Create a New group named OpenMobster
From the mobilecloudlibproject, DragnDrop/Copy all the resources located under the app-bundle
group

Add the libraries and Frameworks


In the Frameworks group add the following library and Frameworks
libmobilecloudlib.a - OpenMobster static library
CoreData.framework
CFNetwork.framework
CoreGraphics.framework
UIKit.framework

32

iOS + OpenMobster integration

Add OpenMobster bootstrap code


Before OpenMobster runtime can be used within an App. It must be bootstrapped and started. The
following code shows how this bootstrapping process works.

The bootstrapping functions


Start Cloud Service

-(void)startCloudService
{
@try
{
CloudService *cloudService = [CloudService getInstance];
[cloudService startup];
}
@catch (NSException * e)
{
//something caused the kernel to crash
//stop the kernel
[self stopCloudService];
}
}

Stop Cloud Service

-(void)stopCloudService
{
@try
{
CloudService *cloudService = [CloudService getInstance];
[cloudService shutdown];
}
@catch (NSException *e)
{
}
}

Start Device Activation if it is not activated with the Cloud already

-(void)startActivation

33

iOS + OpenMobster integration

{
@try
{
CloudService *cloudService = [CloudService getInstance];
[cloudService forceActivation:self.window.rootViewController];
}
@catch (NSException * e)
{
//something caused the kernel to crash
//stop the kernel
[self stopCloudService];
}
}

Do a Sync at Startup

-(void)sync
{
CommandContext *commandContext = [CommandContext withInit:self.viewController];
BackgroundSyncCommand *syncCommand = [BackgroundSyncCommand withInit];
[commandContext setTarget:syncCommand];
CommandService *service = [CommandService getInstance];
[service execute:commandContext];
}

Integrating the bootstrapping function with the App


Delegate
- (BOOL) application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSD


{
//OpenMobster bootstrapping
[self startCloudService];
[self sync];
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]

// Override point for customization after application launch.


if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
self.viewController = [[[ViewController alloc] initWithNibName:@"ViewContro

34

iOS + OpenMobster integration

}
else
{

self.viewController = [[[ViewController alloc] initWithNibName:@"ViewContro


}

//setup the NavigationController


self.navigationController = [[UINavigationController alloc] initWithRootViewCon
//Add the CloudManager button to the navbar
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Cloud Manager"

self.navigationController.topViewController.navigationItem.leftBarButtonItem = but
[button release];

//Add the Create button to the nav bar


UIBarButtonItem *create = [[UIBarButtonItem alloc] initWithTitle:@"Create" styl

self.navigationController.topViewController.navigationItem.rightBarButtonItem = cr
[create release];

self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];

//OpenMobster bootstrapping
[self startActivation];
//Register the App for Push notifications
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound)];

return YES;
}

-(void)applicationWillEnterForeground:(UIApplication *)application

- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the inactive state; he
*/
//OpenMobster bootstrapping
[self sync];

35

iOS + OpenMobster integration

if(!self.pushRegistered)
{
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound)];
}
}

-(void)applicationWillTerminate:(UIApplication *)application

- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
//OpenMobster bootstrapping
[self stopCloudService];
}

Integrating the CloudManager


As an App Developer you can integrate the CloudManager functionality within your App. The
CloudManager is an administrative GUI tool that allows some provisioning functions. You can activate
your device with the Cloud and you can manage the Sync Channels used by your App. This can come in
handy when you want to do some Manual Syncing in case there are issues happening with the automatic
Sync process.
This GUI layer integration is done by activating the Modal,View,Controller CloudManager component.
Here are the integration steps

Integrate the CloudManager button on the View

//setup the NavigationController


self.navigationController = [[UINavigationController alloc] initWithRootViewControl

//Add the CloudManager button to the navbar


UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Cloud Manager" s

self.navigationController.topViewController.navigationItem.leftBarButtonItem = butt
[button release];

36

iOS + OpenMobster integration

Implement the action behind the button


-(IBAction)launchCloudManager:(id)sender
{
//Launch the CloudManager App
[CloudManager modalCloudManager:self];
}

Sample App
In the OpenMobster distribution, you can find an iOS/OpenMobster Sync App under iphone/SampleApp.
On the Cloud Side, the App to run is located under iphone/showcase/cloud. You run the Cloud Server
using the command

mvn -PrunCloud integration-test

37

Chapter 11. iOS + OpenMobster


Sample App
openmobster at gmail.com <openmobster@gmail.com>

Introduction
This chapter covers the steps involved in running the iOS + OpenMobster based Sample App

Prepare the mobilecloudlib static library


Open
the
mobilecloudlib
mobilecloudlib.xcodeproj

XCode

project

by

opening:

iPhone/mobilecloudlib/

Build the project in XCode


For some reason, building the mobilecloudlib fail to compile if your XCode code location is set to the
recommended setting of "Derived Data". You must change this option to "Location Specified By Targets".
Please take a look at this thread for details: https://groups.google.com/forum/#!searchin/openmobsterusers/mobilecloudlib/openmobster-users/zJhJKbFekLs/WiNWtKfG_RcJ

Run the Cloud Server


Go to iphone/showcase/cloud. Under this directory issue the following command to start the Cloud Server
required by the sample app

mvn -PrunCloud integration-test

Run the SampleApp


Open the XCode project located under iphone/SampleApp. Build the project to make sure there are no
errors. Once the Build is successful, Run the project. If this is the first time running the App, it will present
a device activation screen. This is to securely setup your Cloud account so that you can acess the Enterprise
resources in the Cloud. It asks the following information

Cloud IP: The IP address of the Cloud Server


Port: The port that the Cloud Server is running on (1502, by default)
Email Address: Your email address to uniquely identify you with the Cloud
Password: Your password to authenticate with the Cloud

This is a one time activation across all your apps.

38

Chapter 12. Device-To-Device Push


Framework
openmobster at gmail.com <openmobster@gmail.com>

Introduction
OpenMobster 2.2-M7, introduces a new device to device push framework. Using this framework
developers can write Apps which communicate with other devices in the cloud and vice versa. Some
applications of this would be a Chat App or an Instant Messaging App.

Integration
Step 1: Extend
org.openmobster.android.api.d2d.D2DActivity
Override the onStart method to start the CloudService

@Override
protected void onStart()
{
super.onStart();
CloudService.getInstance().start(this);
}

Implement the callback method to handle the GUI aspects of receiving an incoming push message

public void callback(D2DMessage message)


{
//Append a newly received message from the chat system
LinearLayout layout = (LinearLayout)ViewHelper.findViewById(MainAct
TextView chatView = new TextView(MainActivity.this);
chatView.setText(message.getMessage());
layout.addView(chatView);

Toast.makeText(MainActivity.this, message.getMessage(), Toast.LENGT


TextView user = (TextView)ViewHelper.findViewById(this, "user");
user.setText(message.getFrom());
this.to = message.getFrom();
}

39

Device-To-Device Push Framework

Step 2: Configuration
In AndroidManifest.xml, register the org.openmobster.android.api.d2d.D2DReceiver broadcast
receiver

<receiver android:name="org.openmobster.android.api.d2d.D2DReceiver">
<intent-filter>
<!-- action should be d2d://{packagename} of the App -->
<action android:name="d2d://com.chat.android.app" />
</intent-filter>
</receiver>

Also
in
AndroidManifest.xml,
register
the
org.openmobster.core.mobileCloud.api.ui.framework.push.PushBroadcastReceiver to receive and
notify arrival of Push messages

<receiver android:name="org.openmobster.core.mobileCloud.api.ui.framework.pus
<intent-filter>
<!-- Action should be the {packagename} of the App-->
<action android:name="com.chat.android.app"/>
</intent-filter>
</receiver>

In openmobster-app.xml, configure the Push settings as follows:

<app-conf>
<encryption>false</encryption>
<push>

<launch-activity-class>org.openmobster.app.MainActivity</launch-act
<icon-name>push</icon-name>
</push>
</app-conf>

launch-activity-class: Is the Activity that must be launched when a Push notification is clicked
icon-name: Is the icon to display with the Push notification

Step 3: Sample App


The OpenMobster, 2.2-M7 binary distribution comes packaged with a sample application for the DeviceTo-Device Push Framework. It is a simple Chat app and its goal is to show how the framework should
be used to build more complex app. The app is located under AppCreator/sampleApps/chat

40

Chapter 13. PhoneGap: Offline Web


Apps using the Sync Plugin
openmobster at gmail.com <openmobster@gmail.com>

Introduction
PhoneGap [http://www.phonegap.com] 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.

Offline App Usage


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

41

PhoneGap: Offline Web


Apps using the Sync Plugin
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"
},
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,

42

PhoneGap: Offline Web


Apps using the Sync Plugin
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"
},
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)
{

43

PhoneGap: Offline Web


Apps using the Sync Plugin
},
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)

44

PhoneGap: Offline Web


Apps using the Sync Plugin
{
},
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

Update 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)
{

45

PhoneGap: Offline Web


Apps using the Sync Plugin

},
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)

46

PhoneGap: Offline Web


Apps using the Sync Plugin
{
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
public class JQueryBean implements MobileBean,Serializable
{
@MobileBeanId
private String 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 of the MobileBean implementation

public class JQueryBean implements MobileBean,Serializable


{
@MobileBeanId
private String oid;
private
private
private
private

String
String
String
String

title;
customer;
specialist;
comments;

public JQueryBean()
{

47

PhoneGap: Offline Web


Apps using the Sync Plugin
}
public String getOid()
{
return oid;
}
public void setOid(String oid)
{
this.oid = oid;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getCustomer()
{
return customer;
}
public void setCustomer(String customer)
{
this.customer = customer;
}
public String getSpecialist()
{
return specialist;
}
public void setSpecialist(String specialist)
{
this.specialist = specialist;
}
public String getComments()
{
return comments;
}
public void setComments(String comments)
{
this.comments = comments;
}
}

48

PhoneGap: Offline Web


Apps using the Sync Plugin

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.pho
public class PluginJQueryChannel implements Channel

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
public List<? extends MobileBean> readAll()
{
Collection<Object> all = this.objectStore.readAll();
List<JQueryBean> beans = new ArrayList<JQueryBean>();
if(all != null && !all.isEmpty())
{
for(Object bean:all)
{
beans.add((JQueryBean)bean);
}
}
return beans;
}
@Override
public List<? extends MobileBean> bootup()
{
return this.readAll();
}
@Override
public MobileBean read(String id)
{
return (JQueryBean)this.objectStore.read(id);
}

Create the MobileBean

49

PhoneGap: Offline Web


Apps using the Sync Plugin

@Override
public String create(MobileBean mobileBean)
{
JQueryBean toCreate = (JQueryBean)mobileBean;
return this.objectStore.save(toCreate.getOid(), toCreate);
}

Update the MobileBean

@Override
public void update(MobileBean mobileBean)
{
JQueryBean toUpdate = (JQueryBean)mobileBean;
this.objectStore.save(toUpdate.getOid(), toUpdate);
}

Delete the MobileBean

@Override
public void delete(MobileBean mobileBean)
{
JQueryBean toDelete = (JQueryBean)mobileBean;
this.objectStore.delete(toDelete.getOid());
}

50

Chapter 14. PhoneGap + iOS +


OpenMobster integration
openmobster at gmail.com <openmobster@gmail.com>

Introduction
PhoneGap [http://www.phonegap.com] 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 setup an iOS app for development using
the SyncPlugin for iOS.

Prepare the mobilecloudlib static library


Open
the
mobilecloudlib
mobilecloudlib.xcodeproj

XCode

project

by

opening:

iPhone/mobilecloudlib/

Build the project in XCode


For some reason, building the mobilecloudlib fail to compile if your XCode code location is set to the
recommended setting of "Derived Data". You must change this option to "Location Specified By Targets".
Please take a look at this thread for details: https://groups.google.com/forum/#!searchin/openmobsterusers/mobilecloudlib/openmobster-users/zJhJKbFekLs/WiNWtKfG_RcJ

Start a Cordova-based App


Go to File>New Project. In the displayed project templates select the Cordova-based Application and
follow the wizard

Copy JSON components to the App


Create a New Folder called JSON
Go to the mobilecloudlib project and Drag n Drop/Copy all the .h and .m files in the JSON folder to
the JSON folder in your PhoneGap app

Create a Group called OpenMobster


Create a New group named OpenMobster
From the mobilecloudlibproject, DragnDrop/Copy all the resources located under the app-bundle
group

Add the libraries and Frameworks


In the Frameworks group add the following library and Frameworks

51

PhoneGap + iOS +
OpenMobster integration
libmobilecloudlib.a - OpenMobster static library
CoreData.framework
CFNetwork.framework
CoreGraphics.framework
UIKit.framework

Add OpenMobster bootstrap code


Before OpenMobster runtime can be used within an App. It must be bootstrapped and started. The
following code shows how this bootstrapping process works.

The bootstrapping functions


Start Cloud Service

-(void)startCloudService
{
@try
{
CloudService *cloudService = [CloudService getInstance];
[cloudService startup];
}
@catch (NSException * e)
{
//something caused the kernel to crash
//stop the kernel
[self stopCloudService];
}
}

Stop Cloud Service

-(void)stopCloudService
{
@try
{
CloudService *cloudService = [CloudService getInstance];
[cloudService shutdown];
}
@catch (NSException *e)
{
}

52

PhoneGap + iOS +
OpenMobster integration
}

Start Device Activation if it is not activated with the Cloud already

-(void)startActivation
{
@try
{
CloudService *cloudService = [CloudService getInstance];
[cloudService forceActivation:self.viewController];
}
@catch (NSException * e)
{
//something caused the kernel to crash
//stop the kernel
[self stopCloudService];
}
}

Do a Sync at Startup

-(void)sync
{
CommandContext *commandContext = [CommandContext withInit:self.viewController];
BackgroundSyncCommand *syncCommand = [BackgroundSyncCommand withInit];
[commandContext setTarget:syncCommand];
CommandService *service = [CommandService getInstance];
[service execute:commandContext];
}

Integrating the bootstrapping function with the App


Delegate
- (BOOL) application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions

- (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSD


{
//OpenMobster bootstrapping
[self startCloudService];

53

PhoneGap + iOS +
OpenMobster integration
[self sync];
NSURL* url = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
if (url && [url isKindOfClass:[NSURL class]]) {
self.invokeString = [url absoluteString];
NSLog(@"PhoneGapSyncApp launchOptions = %@", url);
}
CGRect screenBounds = [[UIScreen mainScreen] bounds];
self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
self.window.autoresizesSubviews = YES;
CGRect viewBounds = [[UIScreen mainScreen] applicationFrame];
self.viewController = [[[MainViewController alloc] init] autorelease];
self.viewController.useSplashScreen = YES;
self.viewController.wwwFolderName = @"www";
self.viewController.startPage = @"index.html";
self.viewController.view.frame = viewBounds;
// over-ride delegates
self.viewController.webView.delegate = self;
self.viewController.commandDelegate = self;

// check whether the current orientation is supported: if it is, keep it, rathe
BOOL forceStartupRotation = YES;
UIDeviceOrientation curDevOrientation = [[UIDevice currentDevice] orientation];

if (UIDeviceOrientationUnknown == curDevOrientation) {
// UIDevice isn't firing orientation notifications yet go look at the stat
curDevOrientation = (UIDeviceOrientation)[[UIApplication sharedApplication]
}
if (UIDeviceOrientationIsValidInterfaceOrientation(curDevOrientation)) {
for (NSNumber *orient in self.viewController.supportedOrientations) {
if ([orient intValue] == curDevOrientation) {
forceStartupRotation = NO;
break;
}
}
}

if (forceStartupRotation) {
NSLog(@"supportedOrientations: %@", self.viewController.supportedOrientatio
// The first item in the supportedOrientations array is the start orientati
UIInterfaceOrientation newOrient = [[self.viewController.supportedOrientati
NSLog(@"AppDelegate forcing status bar to: %d from: %d", newOrient, curDevO
[[UIApplication sharedApplication] setStatusBarOrientation:newOrient];
}

[self.window addSubview:self.viewController.view];
[self.window makeKeyAndVisible];

54

PhoneGap + iOS +
OpenMobster integration
//OpenMobster bootstrapping
[self startActivation];
return YES;
}

-(void)applicationWillEnterForeground:(UIApplication *)application

-(void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of transition from the background to the inactive state: here
*/
[self sync];
}

-(void)applicationWillTerminate:(UIApplication *)application

-(void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
See also applicationDidEnterBackground:.
*/
[self stopCloudService];
}

PhoneGapSync App
In the OpenMobster distribution, you can find an iOS/PhoneGap Sync App under iphone/
PhoneGapSyncApp. On the Cloud Side, the App to run is located under iphone/showcase/cloud. You
run the Cloud Server using the command

mvn -PrunCloud integration-test

55

Chapter 15. PhoneGap: Sync Plugin


Reference
openmobster at gmail.com <openmobster@gmail.com>

Introduction
PhoneGap [http://www.phonegap.com] 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 provide a reference guide to the Sync Plugin and how to
use it

ReadAll - window.plugins.sync.readall
Reads all the beans stored in the sync channel
Returns a JSON array of oids associated with the beans
Parameters:
channel: The Sync Channel name where the beans are stored
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

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

56

PhoneGap: Sync Plugin Reference

Get a Property Value window.plugins.sync.value


Reads the value of a property of a bean
Returns the value of the property
Parameters:
channel: The Sync Channel name where the beans are stored
oid: unique oid of the targeted bean
property: The property of the bean
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

window.plugins.sync.value(channel,oid,'property',
function(value)
{
console.log(value);
},
function(error)
{
alert(error);
}
);

Execute Query Match All window.plugins.sync.queryByMatchAll


Queries the Sync Channel for beans such that all name/value pairs from the search criteria have to match
Returns a JSON Array of oids of beans that match the criteria
Parameters:
channel: The Sync Channel name where the beans are stored
criteria: JSON name/value pairs to match against
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

57

PhoneGap: Sync Plugin Reference

window.plugins.sync.queryByMatchAll(channel,{'title':'titleValue','comments':
function(matchedOids)
{
if(matchedOids == '0')
{
alert('No Records Found!!!');
return;
}
var oids = JSON.parse(matchedOids);
},
function(error)
{
}
);

Execute Query Match Atleast One window.plugins.sync.queryByMatchOne


Queries the Sync Channel for beans such that atleast one of the name/value pairs from the search criteria
have to match
Returns a JSON Array of oids of beans that match the criteria
Parameters:
channel: The Sync Channel name where the beans are stored
criteria: JSON name/value pairs to match against
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

window.plugins.sync.queryByMatchOne(channel,{'title':'titleValue','comments':
function(matchedOids)
{
if(matchedOids == '0')
{
alert('No Records Found!!!');
return;
}
var oids = JSON.parse(matchedOids);
},

58

PhoneGap: Sync Plugin Reference

function(error)
{
}
);

Execute Query Do Not Match All window.plugins.sync.queryByNotMatchAll


Queries the Sync Channel for beans such that instances that do not match all the name/value pairs of the
criteria are returned
Returns a JSON Array of oids of beans that do not match the criteria
Parameters:
channel: The Sync Channel name where the beans are stored
criteria: JSON name/value pairs to match against
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

window.plugins.sync.queryByNotMatchAll(channel,{'title':'titleValue','comment
function(matchedOids)
{
if(matchedOids == '0')
{
alert('No Records Found!!!');
return;
}
var oids = JSON.parse(matchedOids);
},
function(error)
{
}
);

Execute Query Do Not Match Even One window.plugins.sync.queryByNotMatchOne


Queries the Sync Channel for beans such that instances that do not match even one of the name/value pairs
of the criteria are returned

59

PhoneGap: Sync Plugin Reference

Returns a JSON Array of oids of beans that do not match the criteria
Parameters:
channel: The Sync Channel name where the beans are stored
criteria: JSON name/value pairs to match against
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

window.plugins.sync.queryByNotMatchOne(channel,{'title':'titleValue','comment
function(matchedOids)
{
if(matchedOids == '0')
{
alert('No Records Found!!!');
return;
}
var oids = JSON.parse(matchedOids);
},
function(error)
{
}
);

Execute Query Match Contains All window.plugins.sync.queryByContainsAll


Queries the Sync Channel for beans such that all of the name/value pairs from the search criteria have to
match. The comparison is made such that the criteria value is contained within the property being matched
against.
Returns a JSON Array of oids of beans that match the criteria
Parameters:
channel: The Sync Channel name where the beans are stored
criteria: JSON name/value pairs to match against
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

60

PhoneGap: Sync Plugin Reference

window.plugins.sync.queryByContainsAll(channel,{'title':'title','comments':'c
function(matchedOids)
{
if(matchedOids == '0')
{
alert('No Records Found!!!');
return;
}
var oids = JSON.parse(matchedOids);
},
function(error)
{
}
);

Execute Query Match Contains Atleast One window.plugins.sync.queryByContainsOne


Queries the Sync Channel for beans such that atleast one of the name/value pairs from the search criteria
have to match. The comparison is made such that the criteria value is contained within the property being
matched against.
Returns a JSON Array of oids of beans that match the criteria
Parameters:
channel: The Sync Channel name where the beans are stored
criteria: JSON name/value pairs to match against
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

window.plugins.sync.queryByContainsOne(channel,{'title':'title','comments':'c
function(matchedOids)
{
if(matchedOids == '0')
{
alert('No Records Found!!!');
return;
}
var oids = JSON.parse(matchedOids);

61

PhoneGap: Sync Plugin Reference

},
function(error)
{
}
);

Add a New Bean into the Sync Channel window.plugins.sync.addNewBean


Adds a New Bean into the Sync Channel. The method returns with a temporary oid to reference this bean
by. A permanent oid is assigned to the bean once it is synchronized with the Cloud
Returns a temporary oid to work with this bean before commit/synchronization
Parameters:
channel: The Sync Channel name where the beans are stored
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

window.plugins.sync.addNewBean(channel,
function(tempOid)
{
console.log('Temporary Oid: '+tempOid);
//set the title
window.plugins.sync.updateBean(channel,tempOid,'title','/test/newbean',
function(success)
{
},
function(error){
alert('Setting the Title: '+error);
}
);

//insert into a string array


window.plugins.sync.insertIntoArray(channel,tempOid,'customers',{'string':'/test
function(success)
{
},
function(error)
{
alert('InsertIntoStringArray: '+error);
}
);

62

PhoneGap: Sync Plugin Reference

//insert into an object array


window.plugins.sync.insertIntoArray(channel,tempOid,'messages',{'from':'from@tes
function(success)
{
},
function(error)
{
alert('InsertIntoObjectArray: '+error);
}
);
},
function(error)
{
alert(error);
});
//Commit here
window.plugins.sync.commit(function(success)
{
alert('Commit successful');
},
function(error){});

Update a Bean in the Sync Channel window.plugins.sync.updateBean


Updates the specified property of a bean in the Sync Channel
Returns nothing
Parameters:
channel: The Sync Channel name where the beans are stored
oid: The unique identifier of the bean
property: The property of the bean to be updated
value: The new value of the property
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

window.plugins.sync.updateBean(channel,oid,'title','title://updated',
function(success){
window.plugins.sync.value(channel,oid,'title',

63

PhoneGap: Sync Plugin Reference

function(value)
{
console.log(value);
},
function(error)
{
alert('Reading the Title:'+error);
}
);
},
function(error){
alert('Updating Title: '+error);
}
);
//Commit here
window.plugins.sync.commit(function(success)
{
alert('Commit successful');
},
function(error){});

Delete a Bean from the Sync Channel window.plugins.sync.deleteBean


Deletes the specified bean from the Sync Channel
Returns nothing
Parameters:
channel: The Sync Channel name where the beans are stored
oid: The unique identifier of the bean
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

//delete this bean


window.plugins.sync.deleteBean(channel,oid,
function(success){
},
function(error){
alert(error);
}
);

64

PhoneGap: Sync Plugin Reference

//Commit here
window.plugins.sync.commit(function(success)
{
alert('Commit successful');
},
function(error){});

Commit the operations with the Sync Channel window.plugins.sync.commit


Commits the operation to the Sync Channel. Upon commit the Sync Engine synchronizes the Channel
with the Cloud
Returns nothing
Parameters:
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

//commit
window.plugins.sync.commit(function(success)
{
alert('Commit successful');
},
function(error)
{
alert(error);
}
);

Get the Length of an Array/List property window.plugins.sync.arrayLength


Retrieves the length/size of an Array/List property of the specified bean
Returns the array length
Parameters:
channel: The Sync Channel name where the beans are stored
oid: The unique identifier of the bean

65

PhoneGap: Sync Plugin Reference

property: The property of the bean


successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

window.plugins.sync.arrayLength(channel,oid,'customers',
function(arrayLength)
{
console.log('ArrayLength: '+arrayLength);
},
function(error)
{
alert(error);
}
);

Insert an object into an Array/List property window.plugins.sync.insertIntoArray


Inserts an object into the array
Returns the new array length after adding the object to the Array/List
Parameters:
channel: The Sync Channel name where the beans are stored
oid: The unique identifier of the bean
property: The property of the bean
value: The object in JSON format
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

window.plugins.sync.insertIntoArray(channel,oid,'customers',{'string':'insert
function(arrayLength)
{
},
function(error)
{
alert('InsertIntoArray: '+error);

66

PhoneGap: Sync Plugin Reference

}
);

Clear the entries inside an Array/List property window.plugins.sync.clearArray


Clears all the entries inside the Array/List property
Returns nothing
Parameters:
channel: The Sync Channel name where the beans are stored
oid: The unique identifier of the bean
property: The property of the bean
successCallback:function that will be invoked if this call is successful
errorCallback:function that will be invoked if this call fails
Usage Example:

//clear this array


window.plugins.sync.clearArray(channel,oid,'customers',
function(success)
{
},
function(error)
{
alert(error);
}
);

67

Chapter 16. Location Aware Apps


openmobster at gmail.com <openmobster@gmail.com>

Location Aware Apps


This tutorial covers developing Location Aware Apps using the new Location Module of the
OpenMobster platform. Location Awareness means writing your business logic by taking Location
information into account.
In OpenMobster, the business components are encapsulated with this Location information. The
components then have easy access to the Location data and can easily integrate it with the business data.

LocationServiceBean
On the Cloud-side, LocationServiceBean components are encapsulated by Location Data carried inside
an object called the LocationContext. Invocation of these components involves two paramaters. One is
the LocationContext and the other is a Request object which carries the business data associated with the
invocation. The following is a RestaurantBean which provides coupon data associated with restaurants
that are close to a certain user provided location.

import
import
import
import

java.util.HashMap;
java.util.List;
java.util.Map;
java.util.Random;

import
import
import
import
import
import

org.openmobster.cloud.api.location.LocationContext;
org.openmobster.cloud.api.location.LocationServiceBean;
org.openmobster.cloud.api.location.BeanURI;
org.openmobster.cloud.api.location.Request;
org.openmobster.cloud.api.location.Response;
org.openmobster.cloud.api.location.Place;

/**
*
* @author openmobster@gmail.com
*/
@BeanURI(uri="restaurants")
public class RestaurantBean implements LocationServiceBean

BeanURI registers this component with the kernel.

@Override
public Response invoke(LocationContext locationContext, Request request)
{
Response response = new Response();

68

Location Aware Apps

//Get coupons associated with each place


List<Place> nearbyPlaces = locationContext.getNearbyPlaces();
if(nearbyPlaces != null && !nearbyPlaces.isEmpty())
{
Map<String,String> coupons = new HashMap<String,String>();
for(Place place:nearbyPlaces)
{
String placeId = place.getId();
//In a real implementation, you can lookup the coupon in the database based on
int couponIndex = (this.random.nextInt())%7;
couponIndex = Math.abs(couponIndex);
String coupon = coupondb[couponIndex];
coupons.put(placeId, coupon);
}
response.setMapAttribute("coupons", coupons);
}
return response;
}

It takes a list of nearby restaurants from the LocationContext and then associates coupons from a database
with each. This business data married with location data is then sent back as a Response object.

The App Side Logic


In this app, the location data is provided by the user in terms of street, city, and zip code. Once this data
is available, an invocation is made from the device to the cloud to get nearby restaurants to this location.

String street = (String)commandContext.getAttribute("street");


String city = (String)commandContext.getAttribute("city");
String zip = (String)commandContext.getAttribute("zip");
//Construct a request for the RestaurantBean
Request request = new Request("restaurants");
LocationContext locationContext = new LocationContext();
locationContext.setRequest(request);
//Add the Address around which the restaurants must be looked up
Address address = new Address();
address.setStreet(street);
address.setCity(city);
address.setZipCode(zip);
locationContext.setAddress(address);
//Narrow search to restaurants
List<String> placeTypes = new ArrayList<String>();
placeTypes.add("food");

69

Location Aware Apps

locationContext.setPlaceTypes(placeTypes);
//Set the search radius
locationContext.setRadius(1000); //1000 meters

//Make the invocation to the Cloud to make a Location Aware search


LocationContext responseContext = LocationService.invoke(request, locationContex
commandContext.setAttribute("locationContext", responseContext);

//Construct a request for the RestaurantBean


Request request = new Request("restaurants");
LocationContext locationContext = new LocationContext();
locationContext.setRequest(request);

A Request object is created and its given the name of the component to invoke which is restaurants in
this case. A LocationContext is also initialized which will carry the location data associated with the
invocation

//Add the Address around which the restaurants must be looked up


Address address = new Address();
address.setStreet(street);
address.setCity(city);
address.setZipCode(zip);
locationContext.setAddress(address);

Create an Address object and assign it to the LocationContext.

//Narrow search to restaurants


List<String> placeTypes = new ArrayList<String>();
placeTypes.add("food");
locationContext.setPlaceTypes(placeTypes);
//Set the search radius
locationContext.setRadius(1000); //1000 meters

Narrow the search to only restaurants over a 1000 meter search radius.

//Make the invocation to the Cloud to make a Location Aware search

70

Location Aware Apps

LocationContext responseContext = LocationService.invoke(re

Invoke the RestaurantBean providing the location data in the LocationContext and business data inside
the Request object.

Processing the Response


Map<String,String> coupons = response.getMapAttribute("coupons");
List<Place> restaurants = locationContext.getNearbyPlaces();

//Add restaurant markers and corresponding coupon information


MyItemizedOverlay restaurantMarkers = new MyItemizedOverlay(marker,map);
for(Place restaurant:restaurants)
{
double latitude = Double.parseDouble(restaurant.getLatitude());
double longitude = Double.parseDouble(restaurant.getLongitude());
GeoPoint point = new GeoPoint((int)(latitude * 1E6), (int)(longitude * 1E6));
OverlayItem item = new OverlayItem(point,restaurant.getName(),coupons.get(resta
restaurantMarkers.addOverlay(item);
}

The coupons being business data are read from the Response object as a Map<String,String>, while the
nearby restaurants being location data are read from the LocationContext.

71

Chapter 17. Mobile RPC (Remote


Procedure Call) Development
openmobster at gmail.com <openmobster@gmail.com>
The MobileService component on the Device-side is used to make synchronous remote service invocations
on registered MobileServerBean instances on the Cloud Server.
At this time, this is a very simple request/response based system whose main design goal is to shield the
App developer from any low level details like making network connections, security, resolving remote
services, marshalling/unmarshalling payload, protocol details, etc.
The next iteration of this component will involve introducing more robust features based on a REST-based
architecture.

Cloud-Side: MobileServiceBean
implementation
MobileServiceBean
is
a
simple
interface
org.openmobster.cloud.api.rpc.MobileServiceBean with a single "invoke" method.
This implementation should carry coarse grained business process logic.

@ServiceInfo(uri="/demo/mobile-rpc")
public class DemoMobileBeanService implements MobileServiceBean
{
private static Logger log = Logger.getLogger(DemoMobileBeanService.class);
public DemoMobileBeanService()
{
}
public Response invoke(Request request)
{
log.info("-------------------------------------------------");
log.info(this.getClass().getName()+" successfully invoked...");
Response response = new Response();
String[] names = request.getNames();
for(String name: names)
{
String value = request.getAttribute(name);
log.info("Name="+name+", Value="+value);
response.setAttribute(name, "response://"+value);
}
log.info("-------------------------------------------------");
return response;
}

72

Mobile RPC (Remote


Procedure Call) Development
}

Cloud-Side: Configuration
Provide the META-INF/openmobster-config.xml that will deploy the "MobileServiceBean" instance into
the Cloud Server.

<?xml version="1.0" encoding="UTF-8"?>

<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="/demo/mobile-rpc" class="org.openmobster.core.examples.rpc.DemoMobileB
</deployment>

Cloud-Side: Packaging and Deployment


Packaging: Package the the above classes and the corresponding META-INF/openmobster-config.xml
into a simple jar file.
Deployment: Deploy this jar file into the "deploy" directory of your JBoss AS instance.

Putting it altogether
Entire MobileServiceBean Example is located at: src/dev-tools/sampleApps/rpcdemo/cloud and
AppCreator/sampleApps/rpcdemo/cloud

App/Device-Side: Invoking the


MobileServiceBean
On the device side inside a Moblet, the remote "MobileServiceBean" instance can be invoked using the
org.openmobster.android.api.rpc.MobileService component

Request request = new Request("/demo/mobile-rpc");


request.setAttribute("param1", "paramValue1");
request.setAttribute("param2", "paramValue2");
MobileService service = new MobileService();
Response response = service.invoke(request);

73

Chapter 18. Management Console


openmobster at gmail.com <openmobster@gmail.com>
OpenMobster, comes with a GWT/SmartGWT based GUI Management Console. This Console can be
used to administrate users, devices, and push services. This tool will evolve over time to include some
management functionality like remote wipe, remote lockdown, etc

GUI Functionality
Create Account
This lets you create an 'Admin' account. This creation has to be approved by another administrator before
you can login.

Devices
This lets you manage your devices such activation, deactivation, etc. As the software matures it may add
more system level functions like remote wipe, remote lock down, etc.

Activate/De-Activate
Activates or Deactivates the 'Device' account. If de-activated, none of the Cloud services will be available
to the device. They will be available as soon as the account is activated.

Re-assign
De-activates the 'Device' account and makes it available to be assigned to another user. This is so that
when a user leaves, his device can be re-assigned to another user.

Administrators
Used for managing the 'Admin' accounts.

Activate/De-Activate
Activates and De-Activates the 'Admin' account.

Push Setup
This is used to configure the Apple Push Notification service. As part of the system, a security certificate
has to be assigned to an application before messages can be pushed to it. This is where your certificate can
be uploaded and assigned to an App. Once this is successful, you can send a test push to your iPhone.

74

Chapter 19. Mobile MVC Framework


openmobster at gmail.com <openmobster@gmail.com>
This is a thick client MVC (Model-View-Controller) framework. It is based on a Rich Internet Application
[http://en.wikipedia.org/wiki/Rich_Internet_application] design principle. At this moment in the evolution
of the mobile space, there isn't a commonly adopted GUI development standard across various mobile
platforms. This results in a lot of App porting activity across platforms. Although this framework is not
designed for (Write Once, Run Anywhere) approach, it abstracts out a lot of the UI Framework plumbing
that would otherwise need to be written, ported and maintained by the developer. The framework abstracts
out some of the low level services into the container such as App bootstrapping, screen navigation, graceful
error handling, and internationalization.
The MVC Framework provides the following features/benefit to an App developer:
An abstraction from the different bootstrapping behavior associated with each native phone platform.
A Command framework used for Event Handling. Abstracts platform-level details related to Event
Dispatch Thread, background processing, etc.
A Navigation framework used to help with screen navigation needs.
A portable way to do "Internationalization".
A context oriented "State Management" system used to handle View level state.

Components
Screen
Screen is an abstraction for an instance of the App screen that must be made visible to the user at a particular
moment in time. The low level Navigation service keeps track of the various screens of an App and provides
services such as navigating to a specified screen, going back to the previous screen, and going to the home
screen. Besides the actual implementation of a "Screen" all services related to a "Screen" are portable
across mobile platforms

public abstract class Screen


{
private String id;
public String getId()
{
return this.id;
}
void setId(String id)
{
this.id = id;
}
public abstract void render();
public abstract Object getContentPane();

75

Mobile MVC Framework

public abstract void postRender();


}

Command
Command is an abstraction for an instance of a GUI Event Handler which receives various callbacks based
on the screen's lifecycle. A command typically puts a business process into motion via accessing various
other services like the Mobile Data Framework components, and/or native platform services. Command
instances are managed by the built-in EventBus of the MVC framework. A Command has the following
life cycle which is managed by the event bus.
doAction: This method is invoked when the actual business logic associated with the command should
be executed.
doViewBefore: This method is invoked prior to doAction. Its executed within an active Event Dispatch
Thread and allows making any visual GUI changes to the screen. Some examples would be putting up
a simple alert dialog, may be draw a status bar, etc
doViewAfter: This method is invoked after doAction is executed. This is also executed within the
context of an Event Dispatch Thread, and allows for making visual GUI changes to the screen.
doViewError: This method is invoked if an App-level exception is encountered during the execution
of this command. Being executed within the context of an Event Dispatch thread, it provides the
opportunity to make appropriate GUI changes to robustly handle the error condition.
The MVC Framework provides two builtin Commands. It provides standard behavior associated with these
commands. This frees the App Developer to focus on the App behavior.

LocalCommand
This tells the system that the business logic executes quickly and will not freeze the UI. In the next iteration
of the system, this component will probably be renamed to: FastCommand

public class DemoLocalCommand implements LocalCommand


{
public void doViewBefore(CommandContext commandContext)
{
Toast.makeText((Activity)commandContext.getAppContext(),
"LocalCommand about to execute........",
Toast.LENGTH_SHORT).show();
}
public void doAction(CommandContext commandContext)
{
try
{
System.out.println("-------------------------------------------------------");
System.out.println("Demo Local Command successfully executed...............");
System.out.println("-------------------------------------------------------");
}
catch(Exception e)
{

76

Mobile MVC Framework

throw new RuntimeException(e.toString());


}
}
public void doViewAfter(CommandContext commandContext)
{
Services.getInstance().getNavigationContext().navigate("local");
}
public void doViewError(CommandContext commandContext)
{
ViewHelper.getOkModal((Activity)commandContext.getAppContext(),
"Error", "DemoLocalCommand had an error!!").show();
}
}

AsyncCommand
This tells the system that the associated business logic executes in the background. This approach is
synonymous to the Ajax [http://en.wikipedia.org/wiki/Ajax_%28programming%29] approach in the Web
Development realm. This is used to make the mobile application more responsive and at the same time
accomplish some critical task of interacting with the remote cloud. The difference between this and
the RemoteCommand is that, this command immediately frees up the UI for other interactions. The
RemoteCommand freezes the UI but shows an in progress dialog. Once the action associated with this
command finishes execution outside the UI thread, it re-establises the view cycle. Any UI changes
associated with the execution of this command are then displayed to the user's screen. Below are some of
many mobile scenarios where an AsyncCommand can come in handy:
Show validation errors inline with user input
Update the current screen with data fetched from the Cloud without showing a busy dialog or freezing
the UI
public final class DemoAsyncCommand implements AsyncCommand
{
public void doViewBefore(CommandContext commandContext)
{
Toast.makeText((Activity)commandContext.getAppContext(),
"AsyncCommand about to execute........",
Toast.LENGTH_SHORT).show();
}
public void doAction(CommandContext commandContext)
{
try
{
//Simulate network latency
Thread.currentThread().sleep(10000);
System.out.println("-------------------------------------------------------");
System.out.println("Demo Async Command successfully executed...............");
System.out.println("-------------------------------------------------------");
}
catch(Exception e)

77

Mobile MVC Framework

{
throw new RuntimeException(e.toString());
}
}
public void doViewAfter(CommandContext commandContext)
{
ViewHelper.getOkModal((Activity)commandContext.getAppContext(),
"Success", "Async Command success...").show();

//An Async Command should not navigate away from the screen that launch it...it c
//Services.getInstance().getNavigationContext().navigate("async");
}
public void doViewError(CommandContext commandContext)
{
ViewHelper.getOkModal((Activity)commandContext.getAppContext(),
"Error", "DemoAsyncCommand had an error!!").show();
}
}

RemoteCommand
This tells the system that the associated business logic executes slowly and must execute in the background.
Usually a RemoteCommand is used when making network calls for data located in the cloud, or may be
other scenarios where there is some form of waiting involved. The system wants to provide the appropriate
user experience/feedback so that the user does not think the device is frozen. It will put up appropriate
status indicators to keep the UI fluid. In the next iteration of the system, this component will probably be
renamed to: BusyCommand

public final class DemoRemoteCommand implements RemoteCommand


{
public void doViewBefore(CommandContext commandContext)
{
Toast.makeText((Activity)commandContext.getAppContext(),
"RemoteCommand about to execute........",
Toast.LENGTH_SHORT).show();
}
public void doAction(CommandContext commandContext)
{
try
{
//Simulate network latency
Thread.currentThread().sleep(10000);
System.out.println("-------------------------------------------------------");
System.out.println("Demo Remote Command successfully executed...............");
System.out.println("-------------------------------------------------------");
}
catch(Exception e)
{

78

Mobile MVC Framework

throw new RuntimeException(e.toString());


}
}
public void doViewAfter(CommandContext commandContext)
{
Services.getInstance().getNavigationContext().navigate("remote");
}
public void doViewError(CommandContext commandContext)
{
ViewHelper.getOkModal((Activity)commandContext.getAppContext(),
"Error", "DemoRemoteCommand had an error!!").show();
}
}

PushCommand
A PushCommand allows the developer to handle Cloud Push at the App level. When the Mobile Cloud
runtime synchronizes the App state with the Cloud in the background, it decides how to route the push
notifications to the respective Apps on the device. An App's PushCommand (if specified) is invoked so
that the App can take necessary action such as showing a dialog box, showing some global screen, etc.
Note: PushCommand should only be used to perform an App-specific action. The Mobile Cloud runtime
automatically takes care of system level notifications like blinking LED, updating the app's icon with an
alert, etc.

public final class PushHandler implements PushCommand


{
public void doViewBefore(CommandContext commandContext)
{
}
public void doAction(CommandContext commandContext)
{
try
{
MobilePush push = commandContext.getPush();
System.out.println("Handling Push----------------------------------------");
System.out.println("Push Updates: "+push.getNumberOfUpdates());
MobileBeanMetaData[] updates = push.getPushData();
if(updates != null)
{
for(MobileBeanMetaData update:updates)
{
System.out.println("Bean: "+update.getId());
}
}
System.out.println("----------------------------------------");
}
catch(Exception e)
{

79

Mobile MVC Framework

e.printStackTrace(System.out);
throw new RuntimeException(e.toString());
}
}

public void doViewAfter(CommandContext commandContext)


{
MobilePush push = commandContext.getPush();
Context context = Registry.getActiveInstance().getContext();
Toast.makeText(context, push.getNumberOfUpdates()+" Updates successfully received
Toast.LENGTH_SHORT).show();
}
public void doViewError(CommandContext commandContext)
{
Context context = Registry.getActiveInstance().getContext();
Toast.makeText(context, this.getClass().getName()+" had an error!!",
Toast.LENGTH_SHORT).show();
}
}

Services
EventBus
The EventBus shields the App Developer from learning the low-level GUI Event Management details.
Each mobile platform has its own methodology for handling GUI events. Typically this revolves around
using the Event Dispatch Thread most efficiently and providing a fluid user experience. Users are far more
sensitive to GUI pauses on a mobile device compared to their traditional desktop. The EventBus frees up
the App Developer to develop high-level App specific components like Screen and Commands, and lets
the EventBus worry about the low-level details.

Navigation
The Navigation service abstracts low-level details about navigating through the various App screens that
will be presented to the user.

Internationalization
The Internationalization service abstracts low-level details about localizing an App. It provides a
platform independent way to package the resource bundles, and a standard API to access the information.
The API is language-portable.

Tutorial
Simple Home Screen
Create a simple Home Screen component. This will be the first screen that will be displayed upon launching
an App.

import java.lang.reflect.Field;

80

Mobile MVC Framework

import
import
import
import
import
import
import
import
import
import
import
import
import

org.openmobster.core.mobileCloud.android.configuration.Configuration;
org.openmobster.core.mobileCloud.android.errors.ErrorHandler;
org.openmobster.core.mobileCloud.android.errors.SystemException;
org.openmobster.core.mobileCloud.android.service.Registry;
org.openmobster.core.mobileCloud.android_native.framework.ViewHelper;
org.openmobster.core.mobileCloud.android_native.framework.events.ListItemCli
org.openmobster.core.mobileCloud.android_native.framework.events.ListItemCli
org.openmobster.core.mobileCloud.api.model.MobileBean;
org.openmobster.core.mobileCloud.api.ui.framework.Services;
org.openmobster.core.mobileCloud.api.ui.framework.command.CommandContext;
org.openmobster.core.mobileCloud.api.ui.framework.navigation.NavigationConte
org.openmobster.core.mobileCloud.api.ui.framework.navigation.Screen;
org.openmobster.core.mobileCloud.api.ui.framework.resources.AppResources;

import
import
import
import
import
import

android.app.Activity;
android.app.ListActivity;
android.view.Menu;
android.view.MenuItem;
android.view.MenuItem.OnMenuItemClickListener;
android.widget.ArrayAdapter;

/**
* @author openmobster@gmail.com
*/
public class HomeScreen extends Screen
{
private Integer screenId;
@Override
public void render()
{
try
{
final Activity currentActivity = (Activity)Registry.getActiveInstance().
getContext();
String layoutClass = currentActivity.getPackageName()+".R$layout";
String home = "home";
Class clazz = Class.forName(layoutClass);
Field field = clazz.getField(home);

this.screenId = field.getInt(clazz);
}
catch(Exception e)
{
SystemException se = new SystemException(this.getClass().getName(), "render", ne
"Message:"+e.getMessage(),
"Exception:"+e.toString()
});
ErrorHandler.getInstance().handle(se);
throw se;
}
}

81

Mobile MVC Framework

@Override
public Object getContentPane()
{
return this.screenId;
}
@Override
public void postRender()
{
ListActivity listApp = (ListActivity)Registry.getActiveInstance().
getContext();
AppResources res = Services.getInstance().getResources();
Configuration configuration = Configuration.getInstance(listApp);

if(!configuration.isActive())
{
ViewHelper.getOkModalWithCloseApp(listApp, "App Error", res.localize("inactive_m
show();
return;
}
//Show the List of the "Demo Beans" stored on the device
if(MobileBean.isBooted("offlineapp_demochannel"))
{
MobileBean[] demoBeans = MobileBean.readAll("offlineapp_demochannel");
String[] ui = new String[demoBeans.length];
for(int i=0,size=ui.length;i<size;i++)
{
ui[i] = demoBeans[i].getValue("demoString");
}
listApp.setListAdapter(new ArrayAdapter(listApp,
android.R.layout.simple_list_item_1,
ui));
//List Listener
ListItemClickListener clickListener = new ClickListener(demoBeans);
NavigationContext.getInstance().addClickListener(clickListener);
}
//Setup the App Menu
this.setMenuItems();
}
private void setMenuItems()
{
Menu menu = (Menu)NavigationContext.getInstance().
getAttribute("options-menu");
if(menu != null)
{
MenuItem resetChannel = menu.add(Menu.NONE, Menu.NONE, 0, "Reset Channel");

82

Mobile MVC Framework

resetChannel.setOnMenuItemClickListener(new OnMenuItemClickListener()
{
public boolean onMenuItemClick(MenuItem clickedItem)
{
//UserInteraction/Event Processing...this is where the Commands can be execute
CommandContext commandContext = new CommandContext();
commandContext.setTarget("/offlineapp/reset");
Services.getInstance().getCommandService().execute(commandContext);
return true;
}
});

MenuItem pushTrigger = menu.add(Menu.NONE, Menu.NONE, 1, "Push Trigger");


pushTrigger.setOnMenuItemClickListener(new OnMenuItemClickListener()
{
public boolean onMenuItemClick(MenuItem clickedItem)
{
//UserInteraction/Event Processing...this is where the Commands can be execute
CommandContext commandContext = new CommandContext();
commandContext.setTarget("/offlineapp/pushtrigger");
Services.getInstance().getCommandService().execute(commandContext);
return true;
}
});

MenuItem rpc = menu.add(Menu.NONE, Menu.NONE, 0, "Make RPC Invocation");


rpc.setOnMenuItemClickListener(new OnMenuItemClickListener()
{
public boolean onMenuItemClick(MenuItem clickedItem)
{
//UserInteraction/Event Processing...this is where the Commands can be execute
CommandContext commandContext = new CommandContext();
commandContext.setTarget("/offlineapp/rpc");
Services.getInstance().getCommandService().execute(commandContext);
return true;
}
});
}
}
private static class ClickListener implements ListItemClickListener
{
private MobileBean[] activeBeans;
private ClickListener(MobileBean[] activeBeans)
{
this.activeBeans = activeBeans;
}
public void onClick(ListItemClickEvent clickEvent)
{
int selectedIndex = clickEvent.getPosition();
MobileBean selectedBean = activeBeans[selectedIndex];

83

Mobile MVC Framework

CommandContext commandContext = new CommandContext();


commandContext.setTarget("/demo/details");
commandContext.setAttribute("selectedBean", selectedBean.getValue("demoString"))
Services.getInstance().getCommandService().execute(commandContext);
}
}
}

Configuration
The Moblet code is packaged in a simple jar file. The configuration is located at: /moblet-app/mobletapp.xml

<moblet-app>
<bootstrap>
<screen>com.offlineApp.android.app.screen.HomeScreen</screen>
</bootstrap>

<!-In Android's case this is not needed for this App...The Android core + OpenM
I stand corrected...Android is actually superior to BlackBerry Platform (atl
<push>
<command>org.openmobster.core.examples.offline.command.PushHandler</command>
</push>
-->

<commands>
<command id="/demo/details">com.offlineApp.android.app.command.DemoDetails</comma
<command id="/offlineapp/pushtrigger">com.offlineApp.android.app.command.PushTrig
<command id="/offlineapp/reset">com.offlineApp.android.app.command.ResetChannel</

<command id="/offlineapp/rpc">com.offlineApp.android.app.command.DemoMobileRPC</c
</commands>
<channels>
<channel>offlineapp_demochannel</channel>
</channels>
</moblet-app>

Putting it all together


Detailed Examples located at: src/dev-tools/sampleApps/offlineapp/app-android, src/devtools/sampleApps/rpcdemo/app-android, and src/mobileCloud/android/2_0/test-suite/nativeframeworktestdrive/src/main

84

You might also like