Enterprise Data Mobilization: Part 2

By  Armeen Mazda,CEO, Appeon — November 24, 2009

In Part 1 of this tutorial series we explored the first steps to take to mobilize enterprise data. In this installment, we'll discuss application design considerations as you architect your system.
 
Architect the System: Application Design Considerations
 
BlackBerry application development is very different from PC-based application even though they share the similar programming skills -- Java. The limited screen and keyboard size, battery life, and CPU/memory capability mandate designing a light, simple, user-friendly and effective application.
 
We worked with our client to identify which database tables absolutely needed to be available to the BlackBerry users. We identified approximately 20 tables of the total 175 in the enterprise database. Some of the 20 tables contained as much as 370,000 rows of data. That's not too much for a modern PC workstation but tremendous for a wireless handheld device like the BlackBerry.
 
Bringing this amount of data down to the device consumes excessive bandwidth and battery life, depletes available storage space on the device, and in general will result in slower response times for the mobile application.
 
Anyway, what BlackBerry user can realistically view and work with so much data?
 
Next we had to figure a way to only bring down relevant data that the user needed for those 20 tables. One way to do this is to create a new table that houses only the relevant data. You could develop some back-end process to replicate the relevant subset of data.
 
In our situation, we wanted to avoid replication of data and minimize the programming work. So we went with a feature of MobiLink that allows partitioning the table for synchronization purpose to the BlackBerry. All that was necessary was to write a small script that instructs MobiLink to filter the table. This design consideration reduced the table from 370,000 rows to a manageable 500 rows on average once propagated to the BlackBerry.
 
Implementation: MobiLink Synchronization
 
Model MobiLink synchronizes with UltraLiteJ utilizing a "synchronization model." A synchronization model basically tells MobiLink what tables to synchronize and how to synchronize (e.g. bi-directional).
 
The synchronization model will capture the database side of our design considerations above. In order to create a synchronization model, first you need create an ODBC data source for your enterprise database and select this as the data source.
 
You will need to select tables that will be synchronized with UltraLiteJ and create the schema. It is important that the table and schema in MobiLink will be consistent with those on UltraLiteJ.
 
Next, you will need to configure the data conflict resolution and the synchronization direction. MobiLink supports row/column conflict resolution and bi-directional/one-way synchronization. After creating the synchronization model you will need to deploy it.
 
The SQL Anywhere deployment guide helps walk you through this whole process in detail but its relatively straightforward and not time-consuming. There are wizards to guide you. The only thing you really need to watch out for when you deploy is selecting the right database type of your remote database, which in case of UltraLiteJ on BlackBerry, you would select "New SQL Anywhere database."
 
 
Another nice feature of MobiLink is that you can incrementally update the model in the future if subsequent changes are required. Once the synchronization model is deployed, it is recommended to cre ate a service for the MobiLink server.
 
This makes it easy to start and stop the deployed model, and supports automatic startup. If you find the service is not working correctly, double-check that the port number is not occupied by other services running on the server. This is a common mistake for users running multiple services on a server.

 
Implementation: Creating the UltraLiteJ Database
Now that we've created our synchronization model in MobiLink, we need to create a database and schema in UltraLiteJ. Then a sync is performed to download the initial set of data from the consolidated database.
 
It is a good idea to design your app so that the first time it is run it creates the database and performs a sync. Creating a database is pretty straightforward. UltraLiteJ provides APIs to do this. Also, when you create a database it is good idea to customize certain settings, such as CacheSize. Below are some code examples to illustrate these concepts:
 
public static Connection createDatabase(boolean reset) {
ConfigObjectStore configObjectStore = null;
// _dbName = "demo_new";
// String databaseName = "demo_new";
Date date1 = new Date();
Date date2;
try {
String dsn = EonStore.getProperty("dsn");
configObjectStore = DatabaseManager
.createConfigurationObjectStore(dsn); configObjectStore.setLazyLoadIndexes(true);
//add for performance
int cacheSize = Integer.parseInt(EonStore.getProperty("cachesize")); configObjectStore.setCacheSize(cacheSize*1000);
System.out.println("-------CacheSize:-----" + cacheSize*1000);
. . .
. . .
}
return _conn;
}
 
Now that the database is created we need to create the schema. You can create the schema programmatically in Java utilizing the APIs provided by UltraLiteJ. Below is an example to illustrate this. While creating the schema, ensure that the tables exactly match those specified in MobiLink:
 
public static void createTable(Connection conn) {
try {
 
ColumnSchema column1, . . .
column1 = table_schema.createColumn("call_number", Domain.VARCHAR, 10);
// char-->varchar column1.setNullable(false);
. . .
// primary_keys
IndexSchema index_schema = table_schema
.createPrimaryIndex("primary_keys");
index_schema.addColumn("call_number", IndexSchema.ASCENDING);
// create index
IndexSchema index1 = table_schema.createIndex("pendcallgccx");
index1.addColumn("gcc_id", IndexSchema.ASCENDING);
. . .
}catch (ULjException uex) {
 
Implementation: UltraLiteJ Data Synchronization
 
In order to perform a sync, you will need to specify the publication name (that refers to your deployed MobiLink synchronization model), provide username and password, provide host and port #, and specify an HTTP buffer size.
 
The larger buffer will provide better performance, but watch out, because not all carriers can support larger buffer size. We found that Sprint/Nextel can only support a maximum buffer size of 512 bytes. Below is an example to illustrate this:
 
_syncParms = _conn.createSyncParms(username, pubname); // mluser,mlpassword
String password = EonStore.getProperty("mlpassword");
_syncParms.setPassword(password);
_syncParms.setSyncObserver(new AppSyncObserver());
_streamParms = _syncParms.getStreamParms();
String port = EonStore.getProperty("port");
_streamParms.setPort(Integer.parseInt(port)); // use your own
String host = EonStore.getProperty("host");
_streamParms.setHost(host.toLowerCase()); // 192.0.3.129 _streamParms.setURLSuffix(suffix);
String buffersize = EonStore.getProperty("buffersize"); _streamParms.setOutputBufferSize(Integer.parseInt(buffersize));
 
Implementation: UltraLiteJ Multi-Threading
 
One useful feature of UltraLiteJ is its support for multiple database threads. This lets you design your application to do multiple simultaneous operations on the UltraLiteJ database in an asynchronous fashion. This helps you to provide a fluid and responsive user operation experience.
 
For example, while UltraLiteJ is performing a sync with MobiLink, you want the user to be able to continue working during this time. In our project, the ability for the user to continue working during device synchronization was a very important consideration since we designed the sync to be performed on a configurable timer basis periodically with default value of 15 minutes.
 
Without multiple database threads, every 15 minutes the user would be locked out of their mobile application and since the syncs are happening in the background the user would be unaware what's going on.
 
To solve this conflict we made the automatic sync run on the backend as a new thread, which will not tie up the main thread the mobile user uses to interact with the user interface. A code snippet is provided below to illustrate this concept. You can also create new threads for other time-consuming activities besides sync that will run on the backend without a user interface, such as saving data. This is highly recommended for highly-transactional mobile applications.
 
// Define the SyncThread function to create a new thread when performing the data synchronization.
package com.appeon.datamanager;
import ianywhere.ultralitej.ULjException;
import com.appeon.common.Eon;
import com.appeon.ui.HEScreens;
public class SyncThread extends Thread {
boolean needRefresh = true;
public SyncThread(){
needRefresh = true;
}
public SyncThread(boolean ref){
needRefresh = ref;
}
public void run() {
try { DataAccess.sync();
if (needRefresh)
HEScreens.getMonitorScreen().refresh();
} catch (ULjException ue) {
Eon.showSyncError(ue.toString());
} catch(Exception e){
Eon.showSyncError(e.toString());
} finally {
}
}
}
. . .
// Call this function when the timer event is triggered.
SyncThread t = new SyncThread();
t.start();
. . .

In Part 3, we'll explore the next steps in the implementation process, including client-side caching, coding business logic, and building the user interface.
 
Armeen Mazda is CEO of consulting firm Appeon.

POST A COMMENT

comments powered by Disqus

RATE THIS CONTENT (5 Being the Best)

12345
Current rating: 0 (0 ratings)

MOST READ STORIES

topics

Must See


FEATURED REPORT

Who Owns Mobility

Less than one decade ago, smartphones and tablets changed workplace technology—virtually overnight. IT lost "control" and users became decision makers. Is it any wonder we are still trying to figure things out, and that the question of  "who owns mobility" remains? This research examines the current state of mobility in an attempt to answer that question.