App Developer Guide 2.4

90
OpenMobster - Mobile Cloud Platform App Developer Guide openmobster at gmail.com

Transcript of App Developer Guide 2.4

Page 1: App Developer Guide 2.4

OpenMobster - Mobile Cloud Platform

App Developer Guide

openmobster at gmail.com

Page 2: App Developer Guide 2.4

OpenMobster - Mobile Cloud Platform: App Developer Guideopenmobster at gmail.com

2.4

Page 3: App Developer Guide 2.4

iii

Table of Contents1. Introduction to OpenMobster - Mobile Cloud Platform .......................................................... 1

Data Synchronization .................................................................................................. 1Real-Time Push Notifications ....................................................................................... 1Mobile RPC (Remote Procedure Call) ............................................................................ 1Management Console .................................................................................................. 1

2. Mobile Programmer's Dilemma ......................................................................................... 2............................................................................................................................... 2WebApp ("Browser based") Development ....................................................................... 2

Advantages ........................................................................................................ 2Disadvantages .................................................................................................... 2

App ("Native") Development ........................................................................................ 3Advantages ........................................................................................................ 3Disadvantages .................................................................................................... 3

Popular Mobile Platforms (in no particular order of preference or market share) ..................... 3Blackberry ......................................................................................................... 3Google Android ................................................................................................. 3iPhone .............................................................................................................. 3Symbian ............................................................................................................ 4Windows Mobile ................................................................................................ 4

............................................................................................................................... 4Back to the Future ...................................................................................................... 4

3. Programming Concepts .................................................................................................... 5Cloud Server ............................................................................................................. 5

Channel ............................................................................................................ 5MobileServiceBean ............................................................................................. 5

Mobile App Frameworks ............................................................................................. 5Mobile Data Framework ...................................................................................... 5Mobile MVC Framework ..................................................................................... 6Mobile Cloud .................................................................................................... 6

4. Architecture ................................................................................................................... 7OpenMobster Architecture ........................................................................................... 7Mobile Cloud Stack .................................................................................................... 8

Sync ................................................................................................................. 8Push ................................................................................................................. 8OfflineApp ........................................................................................................ 8Mobile RPC ...................................................................................................... 9Network ............................................................................................................ 9Database ........................................................................................................... 9Inter-App Bus .................................................................................................... 9

Cloud Server Stack ................................................................................................... 105. Get Started: Hello Mobster ............................................................................................. 12

.............................................................................................................................. 12System Requirements ........................................................................................ 12

Create your first Mobile Cloud App ............................................................................. 12Developing the Channel ............................................................................................. 12

Step 1: Write the HelloSyncBean ......................................................................... 12Step 2: Write the HelloSyncChannel .................................................................... 13Step 3: Configuration ........................................................................................ 15

Developing the Android App ...................................................................................... 16Step 1: Write the HomeScreen ............................................................................ 16Step 2: Configuration ........................................................................................ 16

Page 4: App Developer Guide 2.4

OpenMobster - MobileCloud Platform

iv

Running the App ...................................................................................................... 17JBoss Deployment .................................................................................................... 18

6. Production Mode Installation ........................................................................................... 19Cloud-Side: Installation .............................................................................................. 19

Install Cloud Server .......................................................................................... 19Device-Side: Installation ............................................................................................ 19

CloudManager App Installation ........................................................................... 197. Sync App Development .................................................................................................. 20

.............................................................................................................................. 20Tutorial ................................................................................................................... 20

Cloud-Side: Channel Development ....................................................................... 20App/Device-Side: MobileBean component ............................................................. 24

8. MobileBean .................................................................................................................. 26MobileBean ............................................................................................................. 26Cloud-Side ............................................................................................................... 26

Specification .................................................................................................... 26Device-Side ............................................................................................................. 26

Accessing a Simple Property .............................................................................. 26Accessing a Nested Property ............................................................................... 26Accessing an Indexed Property (One-Dimensional Array or a java.util.List) ................. 27Iterating through an Indexed Property (One-Dimensional Array or a java.util.List) ......... 27

9. Push Programming ........................................................................................................ 28Sending a Push Notification ........................................................................................ 28Push Setup on an Android App ................................................................................... 28Push Setup on an iOS App ......................................................................................... 29

Apple Provisioning ........................................................................................... 29OpenMobster Provisioning ................................................................................. 29

10. iOS + OpenMobster integration ...................................................................................... 32Introduction ............................................................................................................. 32Prepare the mobilecloudlib static library ....................................................................... 32Start a View-based App ............................................................................................. 32Create a Group called OpenMobster ............................................................................. 32Add the libraries and Frameworks ............................................................................... 32Add OpenMobster bootstrap code ................................................................................ 33

The bootstrapping functions ................................................................................ 33Integrating the bootstrapping function with the App Delegate .................................... 34

Integrating the CloudManager ..................................................................................... 36Integrate the CloudManager button on the View ..................................................... 36Implement the action behind the button ................................................................ 37

Sample App ............................................................................................................. 3711. iOS + OpenMobster Sample App ................................................................................... 38

Introduction ............................................................................................................. 38Prepare the mobilecloudlib static library ....................................................................... 38Run the Cloud Server ................................................................................................ 38Run the SampleApp .................................................................................................. 38

12. PhoneGap: Offline Web Apps using the Sync Plugin ......................................................... 39Introduction ............................................................................................................. 39Offline App Usage .................................................................................................... 39

Running the Cloud Server .................................................................................. 39Cloud Activation .............................................................................................. 39Installing the Offline App .................................................................................. 39

Dissecting the JQuery Offline App .............................................................................. 40Load Synchronized Beans .................................................................................. 40Add a New Bean to the Sync Channel .................................................................. 41

Page 5: App Developer Guide 2.4

OpenMobster - MobileCloud Platform

v

Update an existing Bean in the Sync Channel ........................................................ 43Delete a Bean from the Sync Channel .................................................................. 44

Dissecting the Cloud ................................................................................................. 45The MobileBean ............................................................................................... 45The Channel .................................................................................................... 47

13. PhoneGap + iOS + OpenMobster integration .................................................................... 49Introduction ............................................................................................................. 49Prepare the mobilecloudlib static library ....................................................................... 49Start a Cordova-based App ......................................................................................... 49Copy JSON components to the App ............................................................................. 49Create a Group called OpenMobster ............................................................................. 49Add the libraries and Frameworks ............................................................................... 49Add OpenMobster bootstrap code ................................................................................ 50

The bootstrapping functions ................................................................................ 50Integrating the bootstrapping function with the App Delegate .................................... 51

PhoneGapSync App .................................................................................................. 5314. PhoneGap: Sync Plugin Reference .................................................................................. 54

Introduction ............................................................................................................. 54ReadAll - window.plugins.sync.readall ......................................................................... 54Get a Property Value - window.plugins.sync.value .......................................................... 55Execute Query Match All - window.plugins.sync.queryByMatchAll ................................... 55Execute Query Match Atleast One - window.plugins.sync.queryByMatchOne ....................... 56Execute Query Do Not Match All - window.plugins.sync.queryByNotMatchAll .................... 57Execute Query Do Not Match Even One - window.plugins.sync.queryByNotMatchOne .......... 57Execute Query Match Contains All - window.plugins.sync.queryByContainsAll ................... 58Execute Query Match Contains Atleast One - window.plugins.sync.queryByContainsOne ....... 59Add a New Bean into the Sync Channel - window.plugins.sync.addNewBean ....................... 60Update a Bean in the Sync Channel - window.plugins.sync.updateBean .............................. 61Delete a Bean from the Sync Channel - window.plugins.sync.deleteBean ............................. 62Commit the operations with the Sync Channel - window.plugins.sync.commit ...................... 63Get the Length of an Array/List property - window.plugins.sync.arrayLength ....................... 63Insert an object into an Array/List property - window.plugins.sync.insertIntoArray ................ 64Clear the entries inside an Array/List property - window.plugins.sync.clearArray .................. 65

15. Location Aware Apps ................................................................................................... 66Location Aware Apps ................................................................................................ 66LocationServiceBean ................................................................................................. 66The App Side Logic .................................................................................................. 67

Processing the Response .................................................................................... 6916. Mobile RPC (Remote Procedure Call) Development .......................................................... 70

Cloud-Side: MobileServiceBean implementation ............................................................. 70Cloud-Side: Configuration .......................................................................................... 71Cloud-Side: Packaging and Deployment ........................................................................ 71Putting it altogether ................................................................................................... 71App/Device-Side: Invoking the MobileServiceBean ........................................................ 71

17. Clustering ................................................................................................................... 72Clustering the Cloud Server ........................................................................................ 72

High Availability .............................................................................................. 72Load Balancing ................................................................................................ 72

Setup ...................................................................................................................... 72Configuration ................................................................................................... 72Starting the Cluster ........................................................................................... 73

18. Management Console ................................................................................................... 74.............................................................................................................................. 74GUI Functionality ..................................................................................................... 74

Page 6: App Developer Guide 2.4

OpenMobster - MobileCloud Platform

vi

Create Account ................................................................................................. 74Devices ........................................................................................................... 74Administrators .................................................................................................. 74Push Setup ...................................................................................................... 74

19. Mobile MVC Framework .............................................................................................. 75.............................................................................................................................. 75

Components ..................................................................................................... 75Services .......................................................................................................... 80Tutorial ........................................................................................................... 80

Page 7: App Developer Guide 2.4

1

Chapter 1. Introduction toOpenMobster - Mobile Cloud Platform

openmobster at gmail.com <[email protected]>

OpenMobster is an open source platform for integrating native Mobile Apps with "Cloud" services

It provides the following features:

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

Real-Time Push NotificationsChanges on the Cloud are automatically pushed to the Apps in real time. The Push mechanism uses purenetwork/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 asimple 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 areinvoked via a simple RPC mechanism without any low-level programming like http-client code, clientside REST library, etc on the part of the App developer. There is a simple RPC API that is used for makingthese calls.

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

Page 8: App Developer Guide 2.4

2

Chapter 2. Mobile Programmer'sDilemma

openmobster at gmail.com <[email protected]>

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 ofthe 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 withdifferent architectural rules, and user expectations was born. The notion of native Apps was created. Eventhough "The Browser" is a perfectly mainstream gateway to the Internet on a desktop, the same rule doesnot translate naturally to the mobile environment. In fact that was the very reason why Mobile Internethas been the next big thing atleast for the last 15 yrs. Companies lazily expecting their users to adopt "TheBrowser" on the mobile phone without realizing this is a completely different beast. Its a paradigm shiftin computer programming. The Mobile Computer is turning out to be the next step in evolution of thePersonal Computer.

WebApp ("Browser based") DevelopmentWeb 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 thePC world, the App executes completely on the server, while the mobile browser serves as a dumb terminalrendering just the UI. Some Javascript/Ajax approaches try to add some thickness to the architecture, butfor 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. Samepause on a desktop goes completely ignored.

• Web apps don't have the native look and feel which makes the user experience un-intuitive. Plus, eachbrowser 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 tofeed context sensitive information back into the system unlocks the potential for a whole new worldof computing.

• Some access via javascript and/or browser plugin is available, but it can never replicate the natural feelof accessing the low level platform API.

Page 9: App Developer Guide 2.4

Mobile Programmer's Dilemma

3

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

App ("Native") DevelopmentNative App Development involves developing the App using the programming language and APIsprovided by the native platform. It provides the most flexible approach to implementing complicatedfunctionality and provide the best user experience possible. Here are some of the advantages of developinga 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 isaware 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 particularorder 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)

Page 10: App Developer Guide 2.4

Mobile Programmer's Dilemma

4

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 complexapps 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 providesservices needed to build easy to use, innovative native apps. It takes away the hardwork of writingmiddleware infrastructure, so that the app developer can focus their development effort on implementingtheir business requirements. Here are some of the ways, OpenMobster tries to alleviate some of thedisadvantages of native app development

• The pluggable nature of the Mobile MVC framework makes it easier to port an app across multipleplatforms. Most of the GUI level plumbing is provided by the Mobile Cloud runtime. Only thingthat requires porting are the Screen and Command components that are implemented using the nativeprogramming language/API.

• Having a consistent messaging spec across all the device level components. This makes the API featureslot more consistent and only thing that varies across platform code is the syntax of the programminglanguge.

• Provide the same exact framework API in case where the programming languages are the same. Forinstance, Blackberry OS and Google Android are based on the same 'Java' programming language. Inthat case the API of the various frameworks have the same exact syntax. This cuts down the portingeffort dramatically. Only code that would require porting is the code that uses the low level platformAPI. The code cannot be platform independent, but it can be language-portable.

Back to the FutureThe ideal scenario would be to have a standard API/programming language across all platform for nativeapps. This is highly impractical considering we still have not achieved this in a desktop environment, anda 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 atproviding a standard for developing cross platform native apps, with all the features and services that aredesirable for a native app. However, this is still an on-going effort at the spec level. HTML5 based nativeapps are probably a couple of years away from fruition.

Page 11: App Developer Guide 2.4

5

Chapter 3. Programming Conceptsopenmobster at gmail.com <[email protected]>

Cloud ServerA Cloud Server is the server-side component of the infrastructure that is located in the 'Cloud'. Thesystem provides mobile-oriented features like data synchronization, real-time push, and mobile rpc. Froman architecture standpoint it sits between the mobile device and the actual cloud data services beingmobilized. The Cloud Server provides a Java based Developer API to expose your data services. Here areits programming concepts:

Channel

A Channel serves as a gateway for integrating on-device model/data objects with the server-side backendstorage systems such as relational databases, content repositories, or Enterprise systems like CRMs, ERPsetc. 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-levelstate management, synchronization, or other mobile-oriented issues. The idea is to keep a Channel a purelydata-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 thedeveloper 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 providemore robust REST-based functionality. In any case, the Developer will still be shielded from the low-levelprogramming 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-timepush 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 representson 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 locallymodified beans back with the server, sync concepts like two-way sync, one-way sync etc. The nativeruntime smartly tracks the changes to the local state of the MobileBean and decides which type of syncis needed.

Page 12: App Developer Guide 2.4

Programming Concepts

6

MobileService

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

Mobile MVC FrameworkThis is a thick client MVC (Model-View-Controller) framework. It is based on a Rich InternetApplication [http://en.wikipedia.org/wiki/Rich_Internet_application] design principle. At this point intime of evolution of the mobile space, there isn't a commonly adopted GUI development standard acrossvarious mobile platforms. This results in a lot of App porting activity across platforms. Although thisframework is not designed for (Write Once, Run Anywhere) approach, it abstracts out a lot of the UIFramework 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 componentsin this framework that use a plugin mechanism and receive call backs to perform activities implementedusing 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 particularmoment in time The low level Navigation Manager keeps track of the various screens of an App andprovides services such as navigating to a specified screen, going back to the previous screen, and goingto the home screen. Besides the actual implementation of a "Screen" all services related to a "Screen" areportable across mobile platforms.

Command

Command is an abstraction for an instance of a GUI Event Handler which receives various callbacks basedon the screen's lifecycle A command typically puts a business process into motion via accessing variousother 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 doorfor integrating cross platform GUI frameworks like standard widgets, HTML5 based GUI, etc.

Mobile CloudMobile Cloud is an on-device native system service. It hosts the runtime that is used by the above mentionedApp Frameworks. On platforms that support inter-application communication such as Android, there is asingle instance of a Mobile Cloud which is shared by all the Apps installed on the device. This helps makebetter 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 runtimemust be installed by bundling it with each App. The Mobile Cloud also comes with a Cloud ManagerApp. The Cloud Manager App provides configuration functions such as secure Device Activation, PushManagement, Channel Management, Discovering/Installing new Apps, etc.

Page 13: App Developer Guide 2.4

7

Chapter 4. Architectureopenmobster at gmail.com <[email protected]>

OpenMobster Architecture

Page 14: App Developer Guide 2.4

Architecture

8

Mobile Cloud Stack

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

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

PushPush service manages state updates being sent as notifications from the Cloud Server. This improves themobile user's experience as they do not have to pro-actively check for new information. When relevantinformation becomes available on the server, the user is automatically notified via system notifications likea beep, vibration, etc. Clarification: The Push service is a real time comet based service. The notificationsare 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 specialinfrastructure like the Blackberry Enterprise Server to make this happen.

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

Page 15: App Developer Guide 2.4

Architecture

9

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 ofsynchronization is the best for the current runtime state of the App. The App developer is never exposedto low level synchronization details like two way sync, one way device sync, etc. It coordinates managingthe Push service. It carries the smartness to track the type of data being pushed along with which installedApp on the device needs the notification. The App developer does not have to write any special code toreceive notifications. The moment the data channel for the App is established, all synchronizations andpush notifications are automatically handled by the OfflineApp service.

Mobile RPC

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

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

DatabaseDatabase service manages local data storage details for Apps. Depending on the platform in question ituses 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 Networkservice, its a low-level service used by the Mobile Data Framework components.

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

Page 16: App Developer Guide 2.4

Architecture

10

Cloud Server Stack

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

SyncSync service synchronizes device side App state changes with the backend services where the data actuallyoriginates. 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.

PushPush service monitors data "Channels" for updates. The moment updates are detected, correspondingComet-based notifications are sent back to the device. If the device is out of coverage or disconnected forsome 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 EnterpriseServer to achieve its functionality. Its a pure Comet-based approach via a socket channel with the device.

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

Page 17: App Developer Guide 2.4

Architecture

11

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

SecuritySecurity component provides authentication and authorization services to make sure mobile devicesconnecting to the Cloud Server are in fact allowed to access the system. Every device must be first securelyprovisioned with the system before it can be used. After the device is registered, it is challenged for propercredentials when the device itself needs to be activated. Once the device is activated, all Cloud requestsare properly authenticated/authorized going forward.

Management ConsoleEvery 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 willhave more device management features like remote data wipe, remote locking, remote tracking, etc.

Page 18: App Developer Guide 2.4

12

Chapter 5. Get Started: Hello Mobsteropenmobster at gmail.com <[email protected]>

In the spirit of confidence building when using a new technology, lets start with a simple app. We willcall it the HelloSync app.

System Requirements

Cloud Server

• Java SE JDK v6.0

Create your first Mobile Cloud AppDownload 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 followingmaven 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 componentsetup, 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 ina JBoss AS based OpenMobster instance.

Developing the Channel

Step 1: Write the HelloSyncBeanThe HelloSyncBean is a simple annotated MobileBean that carries the domain level informationthat will be synchronized with the device. This information is encapsulated inside a MobileBeaninstance. It will be used by the native App on the device side. This bean implements theorg.openmobster.cloud.api.sync.MobileBean interface. This is a simple marker interface. It does notrequire any methods to be implemented.

package com.hello.sync;

Page 19: App Developer Guide 2.4

Get Started: Hello Mobster

13

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 HelloSyncChannelA Channel serves as a gateway for integrating on-device model/data objects with the server-side backendstorage systems such as relational databases, email servers, content repositories, or Enterprise systems likeCRMs, ERPs etc. It provides a simple CRUD (Create, Read, Update, and Delete) interface to expose thebackend data. The Channel is specifically designed such that the Developer does not have to worry aboutany low-level state management, and synchronization issues.

For sake of simplicity, we will only implement a small portion of theorg.openmobster.cloud.api.sync.Channel interface.

Implement the org.openmobster.cloud.api.sync.Channel interface

Page 20: App Developer Guide 2.4

Get Started: Hello Mobster

14

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.cloud.api.sync.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

@Overridepublic List<? extends MobileBean> bootup() { List<HelloSyncBean> bootupBeans = new ArrayList<HelloSyncBean>(); //Just using mock data...Usually this will extract the information from a backend service or database 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 asproviding enough information for booting up the App. The rest of the beans are synchronized silently inthe background without requiring any manual intervention or docking the device to a desktop, etc. Thisallows instant usage of the App without having to wait a few hours for all the required data to be loaded.

Implement scanForNew method

@Override

Page 21: App Developer Guide 2.4

Get Started: Hello Mobster

15

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 thebackend connected to by the channel. Based on that it would send the just new bean ids back, or returnnull, if nothing new is available. If something new is available, this information is automatically syncedand 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 islinked via the user identity associated with the device

• lastScanTimestamp: provides when the last scan occurred. This way developer knows to only includebeans that may have been created in the backend since this period in time.

Implement read method

@Overridepublic 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: ConfigurationRegister 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>

Page 22: App Developer Guide 2.4

Get Started: Hello Mobster

16

Developing the Android App

Step 1: Write the HomeScreenUsing the OpenMobster MVC Framework requires at the very least a very basic understanding of AndroidApplication Fundamentals [http://developer.android.com/guide/topics/fundamentals.html]. A high levelunderstanding 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 HomeScreencomponent 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 onlyhighlight the aspect that deals with displaying the HelloSyncBeans that are synchronized between theCloud and the device. This is accomplished using the following snippet of code:

@Overridepublic void postRender(){ ListActivity listApp = (ListActivity)Registry.getActiveInstance(). getContext(); ............. //Show the List of the "HelloSyncBeans" automatically synced and stored on the device //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: ConfigurationConfigure the Sync and Push systems using app-android/src/resources/openmobster-app.xml

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

Page 23: App Developer Guide 2.4

Get Started: Hello Mobster

17

<push> <launch-activity-class>org.openmobster.core.mobileCloud.android_native.framework.ListApp</launch-activity-class> <icon-name>push</icon-name> </push> <!-- Registers the Cloud channels used by the App --> <channels> <channel name='hellosync'/> </channels></app-conf>

Configure the OpenMobster MVC Framework used by this App using app-android/src/resources/moblet-app/moblet-app.xml

<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 Commands are fired in response to events generated by user interactions --> <commands> <command id='/hellosync/reset'>com.hello.sync.app.ResetChannel</command> </commands> </moblet-app>

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

Running the App• Build the whole HelloSync project

mvn clean install

• 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 HelloSync App. Go to the app-androiddirectory and type in:

Page 24: App Developer Guide 2.4

Get Started: Hello Mobster

18

mvn -Papp-hot-deploy install

• Launch the HelloSync App.

• At first launch you will be guided through an Activation process of the App with the Cloud Server.This is a security measure to make sure only securely authenticated users are allowed to access the datain the Cloud.

• You can download the entire HelloSync App here: HelloSyncApp [http://openmobster.googlecode.com/svn/samples/hellosync-2.4.zip]

JBoss DeploymentOnce the App and its corresponding Cloud artifacts are developed and tested end-to-end, you can aggregateall these artifacts into a single jar ready for deployment into a JBoss AS based Cloud Server. Forinstructions on setting up your JBoss instance please see JBoss Setup.

This single artifact when deployed into the JBoss AS based Cloud Server performs all necessaryregistrations with the system and is ready for deploying the app onto a real device via the Internet.

• Go to the moblet module: cd moblet

• Generate the app and deploy into the JBoss AS instance: mvn -Pjboss-install install

Note: Before executing this deployment command you will need to make sure that the jboss.home propertyis properly set to your location of the JBoss 5.1.0.GA AS. You can change this value in the moblet/pom.xml file

Page 25: App Developer Guide 2.4

19

Chapter 6. Production ModeInstallation

openmobster at gmail.com <[email protected]>

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/optimizedinstance for the OpenMobster Cloud Server

• Step 3: In the case of using MySQL5 as the database, modify openmobster-ds.xml according to yourown 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 beable to connect to the server. Even in the case of a simulation environment, the device's browser doesnot 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: InstallationStarting with OpenMobster 2.4, there is no requirement to install the CloudManager App on the device.All you need to do is install your App and it will automatically take care of the Activation process.The CloudManager App does still serve a purpose. The main purpose is to activate device managementfeatures such as: Remote Wipe and Remote Lock. You also get access to the Corporate App Storefunctionality which makes it easy to download/install apps from the OpenMobster App Store.

CloudManager App InstallationIf you have a Cloud Server running and accessible from the Internet, you can simply downloadCloudManager App 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

Installing the Sample Offline App

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

Page 26: App Developer Guide 2.4

20

Chapter 7. Sync App Developmentopenmobster at gmail.com <[email protected]>

A native Mobile App runs within the constraints of its local runtime. A major advantage of this environmentis access to local storage for data associated with the App. If logic is the nervous system of an App, datais 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 MobileBeancomponent on the Device-side to provide the above mentioned offline capabilities to an App

Tutorial

Cloud-Side: Channel DevelopmentA Channel serves as a gateway for integrating on-device model/data objects with the server-side backendstorage systems such as relational databases, content repositories, or Enterprise systems like CRMs, ERPsetc. 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-levelstate management, and synchronization issues.

Step 1:

Define a simple MobileBean to represent a data entity being mobilized. This MobileBean should adhereto 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 type 'String' private String[] demoArray; //used to demonstrate mobilizing of an indexed property that is an 'array'

Page 27: App Developer Guide 2.4

Sync App Development

21

private List<String> demoList; //used to demonstrate mobilizing an indexed property that is a 'list' 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",

Page 28: App Developer Guide 2.4

Sync App Development

22

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 providejust enough information for an App to be functional. This helps with avoiding very long synchronizationsessions. 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);

Page 29: App Developer Guide 2.4

Sync App Development

23

}

create

Creates a new instance of a "MobileBean" within the backend data service. This happens when a newinstance is created on the device and synchronized back with the Cloud. It returns the unique id generatedby 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.

Page 30: App Developer Guide 2.4

Sync App Development

24

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

<deployment xmlns="urn:jboss:bean-deployer:2.0"> <bean name="/offlineapp/demorepo" class="org.openmobster.core.examples.offlineapp.DemoDataRepository"/> <bean name="/offlineapp/demochannel" class="org.openmobster.core.examples.offlineapp.DemoChannel"> <property name="demoRepository"><inject bean="/offlineapp/demorepo"/></property> </bean> </deployment>

Step 4:

Package the the above classes and the corresponding META-INF/openmobster-config.xml into a simplejar 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 in the binary distribution at: Samples/offlineapp/cloud

App/Device-Side: MobileBean componentOn the device side, this data is accessible via the org.openmobster.android.api.sync.MobileBeancomponent. The device-side MobileBean is a generic component which exposes a Cloud-side MobileBeaninformation through a robust interface. Device-side MobileBean component semantic are coveredhere: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 instancesare only proxies that will be loaded seamlessly when they are really needed on-demand. This processhappens 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"); }}

Page 31: App Developer Guide 2.4

Sync App Development

25

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

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

This particular method call reads the "demoString" property of the corresponding Cloud-SideMobileBean instance covered earlier.

• setValue: Updates the field/property of an instance of a bean. A property expression and its value areprovided.

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

For a more detailed coverage of the MobileBean usage, please see some example code in the binarydistribution located at: Samples/offlineapp/app-android

Page 32: App Developer Guide 2.4

26

Chapter 8. MobileBeanopenmobster at gmail.com <[email protected]>

MobileBeanMobileBean is a managed Mobile Component which carries the state of the domain object that it representson the server. It is propagated from the Cloud Server to the mobile device via its corresponding Channelon 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 locallymodified 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-SideOn the Cloud-Side the MobileBean is a simple Java Object that implements theorg.openmobster.cloud.api.sync.MobileBean interface. The MobileBean is processed byits corresponding Channel. Through the channel instances of these beans are serialized into wire formatand propagated to their respective devices. In order to be successfully serialized/deserialized, they shouldfollow 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 ConcreteTypes.

• 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-SideOn 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 extractthe state associated with each instance. It provides various state-oriented operations. The individualproperties of a bean are accessed using simple and intuitive expressions.

Accessing a Simple PropertyFor a simple property myName on a bean, the following expression is used:

MobileBean.getValue("myName");

Accessing a Nested PropertyFor a nested property myAddress.myStreet on a bean, the following expression is used:

Page 33: App Developer Guide 2.4

MobileBean

27

MobileBean.getValue("myAddress.myStreet");

Accessing an Indexed Property (One-Dimensional Arrayor a java.util.List)

For an indexed property "myName" on the "third element" of an Array or List named "users" ona bean, the following expression is used:

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

Iterating through an Indexed Property (One-DimensionalArray 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 appropriatesynchronization mode. As far as the App developer is concerned, they just update this state locally andgo about their business.

Page 34: App Developer Guide 2.4

28

Chapter 9. Push Programmingopenmobster at gmail.com <[email protected]>

Sending a Push NotificationYou can send a push notification from the cloud using the Push API. This API is located on theorg.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 his operating system * * @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 title, String details)

Push Setup on an Android AppYou can setup Push Notification support in your app via two configuration files. Before we go into thosedetails you must understand that there are two types of push notifications. User Initiated Push notificationusing 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.PushBroadcastReceiver"> <intent-filter> <action android:name="org.crud.android.app"/> </intent-filter> </receiver> <receiver android:name="org.openmobster.core.mobileCloud.api.ui.framework.push.SyncPushBroadcastReceiver"> <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 itsthe 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.

Page 35: App Developer Guide 2.4

Push Programming

29

openmobster-app.xml

<push> <launch-activity-class>org.openmobster.core.mobileCloud.android_native.framework.App</launch-activity-class> <icon-name>push</icon-name> </push>

Here, launch-activity-class indicates the activity that must be launched when the user clicks on thenotification 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 AppThis is a guide to integrate the iPhone Apple Push Notification (APN) based system with theOpenMobster? Push Service. It consists of several provisioning steps from the Apple side and integrationvia 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) requiresa certificate for each App registered for Push Notifications. The best instructions for doing theproper 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) andpassword (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 PushNotification Service. This registration is as follows:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch.

Page 36: App Developer Guide 2.4

Push Programming

30

// 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 didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { 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 Registration Error" message:@"Device Token Cloud Registration Failed. Please make sure your device is activated with the Cloud using the ActivationApp. Re-start this App to start the token registration again" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; dialog = [dialog autorelease]; [dialog show]; }}

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

Page 37: App Developer Guide 2.4

Push Programming

31

• 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

Page 38: App Developer Guide 2.4

32

Chapter 10. iOS + OpenMobsterintegration

openmobster at gmail.com <[email protected]>

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

Prepare the mobilecloudlib static library• Open the mobilecloudlib XCode project by opening: iPhone/mobilecloudlib/

mobilecloudlib.xcodeproj

• Build the project in XCode

For some reason, building the mobilecloudlib fail to compile if your XCode code location is set to therecommended 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/openmobster-users/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-bundlegroup

Add the libraries and FrameworksIn the Frameworks group add the following library and Frameworks

• libmobilecloudlib.a - OpenMobster static library

• CoreData.framework

• CFNetwork.framework

• CoreGraphics.framework

• UIKit.framework

Page 39: App Developer Guide 2.4

iOS + OpenMobster integration

33

Add OpenMobster bootstrap codeBefore OpenMobster runtime can be used within an App. It must be bootstrapped and started. Thefollowing 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

Page 40: App Developer Guide 2.4

iOS + OpenMobster integration

34

{ @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 AppDelegate

- (BOOL) application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ //OpenMobster bootstrapping [self startCloudService]; [self sync]; self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // Override point for customization after application launch. if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController_iPhone" bundle:nil] autorelease];

Page 41: App Developer Guide 2.4

iOS + OpenMobster integration

35

} else { self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController_iPad" bundle:nil] autorelease]; } //setup the NavigationController self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; //Add the CloudManager button to the navbar UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Cloud Manager" style:UIBarButtonItemStyleDone target:self.viewController action:@selector(launchCloudManager:)]; self.navigationController.topViewController.navigationItem.leftBarButtonItem = button; [button release]; //Add the Create button to the nav bar UIBarButtonItem *create = [[UIBarButtonItem alloc] initWithTitle:@"Create" style:UIBarButtonItemStyleDone target:self.viewController action:@selector(launchCreateBean)]; self.navigationController.topViewController.navigationItem.rightBarButtonItem = create; [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; here you can undo many of the changes made on entering the background. */ //OpenMobster bootstrapping [self sync];

Page 42: App Developer Guide 2.4

iOS + OpenMobster integration

36

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 CloudManagerAs an App Developer you can integrate the CloudManager functionality within your App. TheCloudManager is an administrative GUI tool that allows some provisioning functions. You can activateyour device with the Cloud and you can manage the Sync Channels used by your App. This can come inhandy when you want to do some Manual Syncing in case there are issues happening with the automaticSync 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 NavigationControllerself.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; //Add the CloudManager button to the navbarUIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Cloud Manager" style:UIBarButtonItemStyleDone target:self.viewController action:@selector(launchCloudManager:)]; self.navigationController.topViewController.navigationItem.leftBarButtonItem = button;[button release];

Page 43: App Developer Guide 2.4

iOS + OpenMobster integration

37

Implement the action behind the button

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

Sample AppIn 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 Serverusing the command

mvn -PrunCloud integration-test

Page 44: App Developer Guide 2.4

38

Chapter 11. iOS + OpenMobsterSample App

openmobster at gmail.com <[email protected]>

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

Prepare the mobilecloudlib static library• Open the mobilecloudlib XCode project by opening: iPhone/mobilecloudlib/

mobilecloudlib.xcodeproj

• Build the project in XCode

For some reason, building the mobilecloudlib fail to compile if your XCode code location is set to therecommended 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/openmobster-users/mobilecloudlib/openmobster-users/zJhJKbFekLs/WiNWtKfG_RcJ

Run the Cloud ServerGo to iphone/showcase/cloud. Under this directory issue the following command to start the Cloud Serverrequired by the sample app

mvn -PrunCloud integration-test

Run the SampleAppOpen the XCode project located under iphone/SampleApp. Build the project to make sure there are noerrors. Once the Build is successful, Run the project. If this is the first time running the App, it will presenta device activation screen. This is to securely setup your Cloud account so that you can acess the Enterpriseresources 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.

Page 45: App Developer Guide 2.4

39

Chapter 12. PhoneGap: Offline WebApps using the Sync Plugin

openmobster at gmail.com <[email protected]>

IntroductionPhoneGap [http://www.phonegap.com] is an HTML5 app platform that allows you to author nativeapplications with web technologies and get access to APIs and app stores. PhoneGap leverages webtechnologies 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 forPhoneGap. The Sync Plugin exposes the native Sync service to the JavaScript layer using the PhoneGapbridge technology. The rest of this chapter will discuss how to use the Sync Plugin using a JQuery basedsample 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 ActivationFor security reasons, before apps can use the OpenMobster Cloud, the device must be registered with thecloud. 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 caninstall 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

Page 46: App Developer Guide 2.4

PhoneGap: Offline WebApps using the Sync Plugin

40

adb install -r JQueryOfflineApp.apk

Dissecting the JQuery Offline App

Load Synchronized Beans

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

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

window.plugins.sync.readall(channel,

Page 47: App Developer Guide 2.4

PhoneGap: Offline WebApps using the Sync Plugin

41

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 functionis successful it returns an array of oids in JSON format. oids are then parse into a JavaScript object usingthe JSON.parse function.

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

window.plugins.sync.value reads the value of the specified title property. It takes the channel name andthe 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) {

Page 48: App Developer Guide 2.4

PhoneGap: Offline WebApps using the Sync Plugin

42

}, 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 updatedand 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 atemporary oid used to refer to this newly added bean.

window.plugins.sync.updateBean(channel,tempoid,'title',title, function(success)

Page 49: App Developer Guide 2.4

PhoneGap: Offline WebApps using the Sync Plugin

43

{ }, 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. Inthis 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) {

Page 50: App Developer Guide 2.4

PhoneGap: Offline WebApps using the Sync Plugin

44

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

Page 51: App Developer Guide 2.4

PhoneGap: Offline WebApps using the Sync Plugin

45

{ 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 forsynchronization with the Cloud.

Dissecting the CloudThe 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 beinjected into the Sync Channel. It will then be accesssed on the device via the Sync Plugin API. TheMobileBeanId annotation specified that the oid field will serve as the unique object identifier for thesebeans.

Full Source of the MobileBean implementation

public class JQueryBean implements MobileBean,Serializable{ @MobileBeanId private String oid; private String title; private String customer; private String specialist; private String comments; public JQueryBean() {

Page 52: App Developer Guide 2.4

PhoneGap: Offline WebApps using the Sync Plugin

46

}

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; }}

Page 53: App Developer Guide 2.4

PhoneGap: Offline WebApps using the Sync Plugin

47

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

@ChannelInfo(uri="plugin_jquery_channel", mobileBeanClass="org.openmobster.core.phonegap.plugin.jquery.cloud.JQueryBean")public class PluginJQueryChannel implements Channel

The ChannelInfo.uri specifies the name of the Sync Channel and ChannelInfo.mobileBeanClassspecifies the class of the MobileBean instance that the channel will be dealing with. The MobileBeaninstances used by the Channel implementation must be instances of this specified class. If this rule is notfollowed 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

Page 54: App Developer Guide 2.4

PhoneGap: Offline WebApps using the Sync Plugin

48

@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()); }

Page 55: App Developer Guide 2.4

49

Chapter 13. PhoneGap + iOS +OpenMobster integration

openmobster at gmail.com <[email protected]>

IntroductionPhoneGap [http://www.phonegap.com] is an HTML5 app platform that allows you to author nativeapplications with web technologies and get access to APIs and app stores. PhoneGap leverages webtechnologies 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 forPhoneGap. The Sync Plugin exposes the native Sync service to the JavaScript layer using the PhoneGapbridge technology. The rest of this chapter will discuss how to setup an iOS app for development usingthe SyncPlugin for iOS.

Prepare the mobilecloudlib static library• Open the mobilecloudlib XCode project by opening: iPhone/mobilecloudlib/

mobilecloudlib.xcodeproj

• Build the project in XCode

For some reason, building the mobilecloudlib fail to compile if your XCode code location is set to therecommended 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/openmobster-users/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 tothe 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-bundlegroup

Add the libraries and FrameworksIn the Frameworks group add the following library and Frameworks

Page 56: App Developer Guide 2.4

PhoneGap + iOS +OpenMobster integration

50

• libmobilecloudlib.a - OpenMobster static library

• CoreData.framework

• CFNetwork.framework

• CoreGraphics.framework

• UIKit.framework

Add OpenMobster bootstrap codeBefore OpenMobster runtime can be used within an App. It must be bootstrapped and started. Thefollowing 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) { }

Page 57: App Developer Guide 2.4

PhoneGap + iOS +OpenMobster integration

51

}

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 AppDelegate

- (BOOL) application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions

- (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions{ //OpenMobster bootstrapping [self startCloudService];

Page 58: App Developer Guide 2.4

PhoneGap + iOS +OpenMobster integration

52

[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, rather than forcing a rotation BOOL forceStartupRotation = YES; UIDeviceOrientation curDevOrientation = [[UIDevice currentDevice] orientation]; if (UIDeviceOrientationUnknown == curDevOrientation) { // UIDevice isn't firing orientation notifications yet… go look at the status bar curDevOrientation = (UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation]; } if (UIDeviceOrientationIsValidInterfaceOrientation(curDevOrientation)) { for (NSNumber *orient in self.viewController.supportedOrientations) { if ([orient intValue] == curDevOrientation) { forceStartupRotation = NO; break; } } } if (forceStartupRotation) { NSLog(@"supportedOrientations: %@", self.viewController.supportedOrientations); // The first item in the supportedOrientations array is the start orientation (guaranteed to be at least Portrait) UIInterfaceOrientation newOrient = [[self.viewController.supportedOrientations objectAtIndex:0] intValue]; NSLog(@"AppDelegate forcing status bar to: %d from: %d", newOrient, curDevOrientation); [[UIApplication sharedApplication] setStatusBarOrientation:newOrient]; } [self.window addSubview:self.viewController.view]; [self.window makeKeyAndVisible];

Page 59: App Developer Guide 2.4

PhoneGap + iOS +OpenMobster integration

53

//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 you can undo many of the changes made on entering the background. */ [self sync];}

-(void)applicationWillTerminate:(UIApplication *)application

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

PhoneGapSync AppIn 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. Yourun the Cloud Server using the command

mvn -PrunCloud integration-test

Page 60: App Developer Guide 2.4

54

Chapter 14. PhoneGap: Sync PluginReference

openmobster at gmail.com <[email protected]>

IntroductionPhoneGap [http://www.phonegap.com] is an HTML5 app platform that allows you to author nativeapplications with web technologies and get access to APIs and app stores. PhoneGap leverages webtechnologies 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 forPhoneGap. The Sync Plugin exposes the native Sync service to the JavaScript layer using the PhoneGapbridge technology. The rest of this chapter will provide a reference guide to the Sync Plugin and how touse it

ReadAll - window.plugins.sync.readallReads 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); } );

Page 61: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

55

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:

Page 62: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

56

window.plugins.sync.queryByMatchAll(channel,{'title':'titleValue','comments':'commentsValue'}, 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 criteriahave 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':'commentsValue'}, function(matchedOids) { if(matchedOids == '0') { alert('No Records Found!!!'); return; } var oids = JSON.parse(matchedOids); },

Page 63: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

57

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 thecriteria 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','comments':'commentsValue'}, 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 pairsof the criteria are returned

Page 64: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

58

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','comments':'commentsValue'}, 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 tomatch. The comparison is made such that the criteria value is contained within the property being matchedagainst.

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:

Page 65: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

59

window.plugins.sync.queryByContainsAll(channel,{'title':'title','comments':'comments'}, 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 criteriahave to match. The comparison is made such that the criteria value is contained within the property beingmatched 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':'comments'}, function(matchedOids) { if(matchedOids == '0') { alert('No Records Found!!!'); return; } var oids = JSON.parse(matchedOids);

Page 66: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

60

}, 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 beanby. 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/newbean/string/array'}, function(success) { }, function(error) { alert('InsertIntoStringArray: '+error); } );

Page 67: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

61

//insert into an object array window.plugins.sync.insertIntoArray(channel,tempOid,'messages',{'from':'[email protected]','to':'[email protected]','message':'you got mail'}, 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',

Page 68: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

62

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

Page 69: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

63

//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 Channelwith 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

Page 70: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

64

• 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);

Page 71: App Developer Guide 2.4

PhoneGap: Sync Plugin Reference

65

} );

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

Page 72: App Developer Guide 2.4

66

Chapter 15. Location Aware Appsopenmobster at gmail.com <[email protected]>

Location Aware AppsThis tutorial covers developing Location Aware Apps using the new Location Module of theOpenMobster platform. Location Awareness means writing your business logic by taking Locationinformation into account.

In OpenMobster, the business components are encapsulated with this Location information. Thecomponents then have easy access to the Location data and can easily integrate it with the business data.

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

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

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

/** * * @author [email protected] */@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();

Page 73: App Developer Guide 2.4

Location Aware Apps

67

//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 the Place object 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 databasewith each. This business data married with location data is then sent back as a Response object.

The App Side LogicIn this app, the location data is provided by the user in terms of street, city, and zip code. Once this datais 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");

Page 74: App Developer Guide 2.4

Location Aware Apps

68

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, locationContext); 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 inthis case. A LocationContext is also initialized which will carry the location data associated with theinvocation

//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

Page 75: App Developer Guide 2.4

Location Aware Apps

69

LocationContext responseContext = LocationService.invoke(request, locationContext);

Invoke the RestaurantBean providing the location data in the LocationContext and business data insidethe 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(restaurant.getId())); restaurantMarkers.addOverlay(item); }

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

Page 76: App Developer Guide 2.4

70

Chapter 16. Mobile RPC (RemoteProcedure Call) Development

openmobster at gmail.com <[email protected]>

The MobileService component on the Device-side is used to make synchronous remote service invocationson 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 theApp developer from any low level details like making network connections, security, resolving remoteservices, marshalling/unmarshalling payload, protocol details, etc.

The next iteration of this component will involve introducing more robust features based on a REST-basedarchitecture.

Cloud-Side: MobileServiceBeanimplementation

MobileServiceBean is a simple interfaceorg.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; }

Page 77: App Developer Guide 2.4

Mobile RPC (RemoteProcedure Call) Development

71

}

Cloud-Side: ConfigurationProvide the META-INF/openmobster-config.xml that will deploy the "MobileServiceBean" instance intothe 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.DemoMobileBeanService"/></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 altogetherEntire MobileServiceBean Example is located at: src/dev-tools/sampleApps/rpcdemo/cloud andAppCreator/sampleApps/rpcdemo/cloud

App/Device-Side: Invoking theMobileServiceBean

On the device side inside a Moblet, the remote "MobileServiceBean" instance can be invoked using theorg.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);

Page 78: App Developer Guide 2.4

72

Chapter 17. Clusteringopenmobster at gmail.com <[email protected]>

Clustering the Cloud ServerYou can setup the OpenMobster Cloud as a highly available Clustered environment.

High Availability

The high availability cluster consists of multiple JBoss nodes of the OpenMobster Cloud Server. Outof these nodes there is a single node that serves as the Master node. All the incoming traffic is directed tothis Master node. The Master node is not a single point of failure because if the Master node goes down,one of the other nodes immediately becomes a Master node. This process keeps going till all the nodes areused up. This is how you can get a highly available cluster running since at any given time there is alwaysone master node processing requests from the mobile devices.

Load Balancing

At this point in time the Master node processes all the incoming requests. It does not delegate any requeststo its other nodes to balance the load. This feature will be supported in a future release. This is a challengebecause it needs to replicate local state among the cluster members. At this point, the Sync service doesnot support this replication except data sharing via the shared database. This is not enough and will requiresome re-architecting to make the service truly stateless. From here on out, all new services developed willsupport load balancing to get the best out of a clustered setup.

SetupThis will cover the steps for setting up an OpenMobster Cloud in a clustered environment

Configuration

In your JBoss server open the following file: deploy/openmobster.last/clustering-2.4-SNAPSHOT.jar/META-INF/openmobster-config.xml. Make sure the file looks as the following to activate the node asa Cluster node

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

<deployment xmlns="urn:jboss:bean-deployer:2.0"> <bean name="clustering://ClusterService" class="org.openmobster.core.cluster.ClusterService"> <!-- Make this value true to activate this node as a Cluster node --> <property name="active">true</property> </bean> </deployment>

Page 79: App Developer Guide 2.4

Clustering

73

Starting the ClusterTo start the cluster you start one node at a time. The first started node starts off as the Master node. Theother nodes remain in standby to become the Master node when/if it goes down. You start the node usingthe standard JBoss command:

./run.sh -c {server-name} -b {node-ipaddress}

Page 80: App Developer Guide 2.4

74

Chapter 18. Management Consoleopenmobster at gmail.com <[email protected]>

OpenMobster, comes with a GWT/SmartGWT based GUI Management Console. This Console can beused to administrate users, devices, and push services. This tool will evolve over time to include somemanagement functionality like remote wipe, remote lockdown, etc

GUI Functionality

Create AccountThis lets you create an 'Admin' account. This creation has to be approved by another administrator beforeyou can login.

DevicesThis lets you manage your devices such activation, deactivation, etc. As the software matures it may addmore 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 availableto 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 thatwhen a user leaves, his device can be re-assigned to another user.

AdministratorsUsed for managing the 'Admin' accounts.

Activate/De-Activate

Activates and De-Activates the 'Admin' account.

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

Page 81: App Developer Guide 2.4

75

Chapter 19. Mobile MVC Frameworkopenmobster at gmail.com <[email protected]>

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 evolutionof the mobile space, there isn't a commonly adopted GUI development standard across various mobileplatforms. This results in a lot of App porting activity across platforms. Although this framework is notdesigned for (Write Once, Run Anywhere) approach, it abstracts out a lot of the UI Framework plumbingthat would otherwise need to be written, ported and maintained by the developer. The framework abstractsout some of the low level services into the container such as App bootstrapping, screen navigation, gracefulerror 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 EventDispatch 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 particularmoment in time. The low level Navigation service keeps track of the various screens of an App and providesservices such as navigating to a specified screen, going back to the previous screen, and going to the homescreen. Besides the actual implementation of a "Screen" all services related to a "Screen" are portableacross 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();

Page 82: App Developer Guide 2.4

Mobile MVC Framework

76

public abstract void postRender();}

Command

Command is an abstraction for an instance of a GUI Event Handler which receives various callbacks basedon the screen's lifecycle. A command typically puts a business process into motion via accessing variousother services like the Mobile Data Framework components, and/or native platform services. Commandinstances are managed by the built-in EventBus of the MVC framework. A Command has the followinglife cycle which is managed by the event bus.

• doAction: This method is invoked when the actual business logic associated with the command shouldbe executed.

• doViewBefore: This method is invoked prior to doAction. Its executed within an active Event DispatchThread and allows making any visual GUI changes to the screen. Some examples would be putting upa simple alert dialog, may be draw a status bar, etc

• doViewAfter: This method is invoked after doAction is executed. This is also executed within thecontext 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 executionof this command. Being executed within the context of an Event Dispatch thread, it provides theopportunity to make appropriate GUI changes to robustly handle the error condition.

The MVC Framework provides two builtin Commands. It provides standard behavior associated with thesecommands. 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 iterationof 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) {

Page 83: App Developer Guide 2.4

Mobile MVC Framework

77

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 issynonymous to the Ajax [http://en.wikipedia.org/wiki/Ajax_%28programming%29] approach in the WebDevelopment realm. This is used to make the mobile application more responsive and at the same timeaccomplish some critical task of interacting with the remote cloud. The difference between this andthe RemoteCommand is that, this command immediately frees up the UI for other interactions. TheRemoteCommand freezes the UI but shows an in progress dialog. Once the action associated with thiscommand finishes execution outside the UI thread, it re-establises the view cycle. Any UI changesassociated with the execution of this command are then displayed to the user's screen. Below are some ofmany 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 freezingthe 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)

Page 84: App Developer Guide 2.4

Mobile MVC Framework

78

{ 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 can result in yucky UI errors //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 beother scenarios where there is some form of waiting involved. The system wants to provide the appropriateuser experience/feedback so that the user does not think the device is frozen. It will put up appropriatestatus indicators to keep the UI fluid. In the next iteration of the system, this component will probably berenamed 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) {

Page 85: App Developer Guide 2.4

Mobile MVC Framework

79

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 Cloudruntime synchronizes the App state with the Cloud in the background, it decides how to route the pushnotifications to the respective Apps on the device. An App's PushCommand (if specified) is invoked sothat 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 runtimeautomatically takes care of system level notifications like blinking LED, updating the app's icon with analert, 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) {

Page 86: App Developer Guide 2.4

Mobile MVC Framework

80

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 aroundusing the Event Dispatch Thread most efficiently and providing a fluid user experience. Users are far moresensitive to GUI pauses on a mobile device compared to their traditional desktop. The EventBus frees upthe App Developer to develop high-level App specific components like Screen and Commands, and letsthe EventBus worry about the low-level details.

Navigation

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

Internationalization

The Internationalization service abstracts low-level details about localizing an App. It provides aplatform 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 launchingan App.

import java.lang.reflect.Field;

Page 87: App Developer Guide 2.4

Mobile MVC Framework

81

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

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

/** * @author [email protected] */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", new Object[]{ "Message:"+e.getMessage(), "Exception:"+e.toString() }); ErrorHandler.getInstance().handle(se); throw se; } }

Page 88: App Developer Guide 2.4

Mobile MVC Framework

82

@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_message","inactive_message")). 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");

Page 89: App Developer Guide 2.4

Mobile MVC Framework

83

resetChannel.setOnMenuItemClickListener(new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem clickedItem) { //UserInteraction/Event Processing...this is where the Commands can be executed 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 executed 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 executed 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];

Page 90: App Developer Guide 2.4

Mobile MVC Framework

84

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/moblet-app.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 + OpenMobster core framework gives everything you need for the usecase on this App.. I stand corrected...Android is actually superior to BlackBerry Platform (atleast upto 4.0.x...have not used 5.0.x yet to have an opinion) <push> <command>org.openmobster.core.examples.offline.command.PushHandler</command> </push> --> <commands> <command id="/demo/details">com.offlineApp.android.app.command.DemoDetails</command> <command id="/offlineapp/pushtrigger">com.offlineApp.android.app.command.PushTrigger</command> <command id="/offlineapp/reset">com.offlineApp.android.app.command.ResetChannel</command> <command id="/offlineapp/rpc">com.offlineApp.android.app.command.DemoMobileRPC</command> </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/dev-tools/sampleApps/rpcdemo/app-android, and src/mobileCloud/android/2_0/test-suite/nativeframework-testdrive/src/main