Chapter 10. Extending the Funambol Data Synchronization Service

The previous chapter covered the SyncML protocol in detail. Funambol uses SyncML as its synchronization protocol to exchange data between the client and server.

This chapter explains how to develop extensions for the Funambol DS Service so that a developer can create integrations with other backend datasources. It will also describe how to build a simple connector, helping us to understand how the Funambol DS Service interacts with server extensions and connectors.

Funambol development

The following sections present several concepts related to how Funambol can be used to build mobile applications. Before digging into the details of Funambol development, it is useful to describe some basic concepts of data synchronization, as it is the foundation for Funambol applications and services. Some of these concepts such as the SyncML protocol were introduced in the previous chapter. In this chapter, those aspects will be described from a more technical perspective.

Data synchronization

All mobile devices—handheld computers, mobile phones, pagers, and laptops—need to synchronize their data with the server where the information is stored. This ability to access and update information on the fly is the key to the pervasive nature of mobile computing. Yet, today almost every device uses a different technology for data synchronization.

Data synchronization is helpful for:

  • Propagating updates between a growing number of applications

  • Overcoming the limitations of mobile devices and wireless connections

  • Maximizing the user experience by minimizing data access latency

  • Keeping scalability of the infrastructure in an environment where the number of devices (clients) and connections tend to increase considerably

  • Understanding the requirements of mobile applications, providing a user experience that is helpful, and not an obstacle, for mobile tasks

Data synchronization is the process of making two sets of data look identical, as shown in the following figure:

Data synchronization

This involves many techniques, which will be discussed in the following sections. The most important are:

  • ID handling

  • Change detection

  • Modification exchange

  • Conflict detection

  • Conflict resolution

  • Slow and fast synchronization

ID handling

At first glance, ID handling seems like a pretty straightforward process that requires little or no attention. However, ID handling is an important aspect of the synchronization process and is not trivial.

In some cases a piece of data is identifiable by a subset of its content fields. For example, in the case of a contact entry, the concatenation of a first name and last name uniquely selects an entry in the directory. In other cases, the ID is represented by a particular field specifically introduced for that purpose. For example, in a Sales Force Automation mobile application, an order is identified by an order number or ID. The way in which an item ID is generated is not predetermined and it may be application or even device specific.

In an enterprise system, data is stored in a centralized database, which is shared by many users. Each single item is recognized by the system because of a unique global ID. In some cases, two sets of data (the order on a client and the order on a server) represent the same information (the order made by the customer) but they differ. What could be done to reconcile client and server IDs to make the information consistent? Many approaches can be chosen:

  • Client and server agree on an ID scheme (a convention on how to generate IDs must be defined and used).

  • Each client generates globally unique IDs (GUIDs) and the server accepts client-generated IDs.

  • The server generates GUIDs and each client accepts those IDs.

  • Client and server generate their own IDs and a mapping is kept between the two. Client-side IDs are called Locally Unique Identifiers (LUID) and server-side IDs are called Globally Unique Identifiers (GUID). The mapping between local and global identifiers is referred as LUID-GUID mapping. The SyncML specifications prescribe the use of LUID-GUID mapping technique, which allows maximum freedom to client implementations.

Change detection

Change detection is the process of identifying the data that was modified after a particular point in time that is, the last synchronization. This is usually achieved by using additional information such as timestamp and state information. For example, a possible database enabled for efficient change detection is shown in the following table:

ID

First name

Last name

Telephone

State

Last_update

12

John

Doe

+1 650 5050403

N

2008-04-02 13:22

13

Mike

Smith

+1 469 4322045

D

2008-04-01 17:32

14

Vincent

Brown

+1 329 2662203

U

2008-03-21 17:29

However, sometimes legacy databases do not provide the information needed to accomplish efficient change detection. As a result, the matter becomes more complicated and alternative methods must be adopted (based on content comparison, for instance). This is one of the most important aspects to consider when writing a Funambol extension, because the synchronization engine needs to know what's changed from a point in time.

Modification exchange

A key component of a data synchronization infrastructure is the way modifications are exchanged between client and server. This involves the definition of a synchronization protocol that client and server use to initiate and execute a synchronization session. In addition to the exchange modification method, a synchronization protocol must also define a set of supported modification commands. The minimal set of modification commands are as follows:

  • Add

  • Replace

  • Delete

Conflict detection

Let's assume that two users synchronize their local contacts database with a central server in the morning before going to the office. After synchronization, the contacts on their smartphones are exactly the same. Let's now assume that they update the telephone number for "John Doe" entry and one of them makes a mistake and enters a different number. What will happen the next morning when they both synchronize again? Which of the two new versions of the "John Doe" record should be taken and stored into the server? This condition is called conflict and the server has the duty of identifying and resolving it.

Funambol detects a conflict by means of a synchronization matrix shown in the following table:

Database A →

↓ Database B

New

Deleted

Updated

Synchronized/

Unchanged

Not Existing

New

C

C

C

C

B

Deleted

C

X

C

D

X

Updated

C

C

C

B

B

Synchronized/ Unchanged

C

D

A

=

B

Not Existing

A

X

A

A

X

As both users synchronize with the central database, we can consider what happens between the server database and one of the client databases at a time. Let's call Database A, as the client database and Database B, as the server database. The symbols in the synchronization matrix have the following meaning:

  • X: Do nothing

  • A: Item A replaces item B

  • B: Item B replaces item A

  • C: Conflict

  • D: Delete the item from the source(s) containing it

Conflict resolution

Once a conflict arises and is detected, proper action must be taken. Different policies can be applied. Let's see some of them:

  • User decides: The user is notified of the conflict condition and decides what to do.

  • Client wins: The server silently replaces conflicting items with the ones sent by the client.

  • Server wins: The client has to replace conflicting items with the ones from the server.

  • Timestamp based: The last modified (in time) item wins.

  • Last/first in wins: The last/first arrived item wins.

  • Merge: Try to merge the changes, at least when there is no direct conflict. Consider the case of a vcard, where two concurrent modifications have been applied to two different fields. There is a conflict at the card level, but the two changes can be merged so that both clients can then have a valid version of the card. This is the best example of the case when the change is not directly conflicting.

  • Do not resolve.

Note

Note that Funambol adopts a special merging policy that guarantees that the user does not lose data. The server always tries to merge if possible. When a conflict cannot be resolved with merging (for example, there are conflicting changes on the same field), the value in the last synchronization wins over the older synchronizations to meet the expectation of the user who is synchronizing. In this way, when the users who applied previous changes receive the new updates all devices will be in sync.

Synchronization modes: Full or fast

As seen in the previous chapter, there are many modes to carry out the synchronization process. The main distinction is between fast and full synchronization. Fast synchronization involves only the items changed since the last synchronization between two devices. Of course, this is an optimized process that relies on the fact that, the devices were fully synchronized at some point in the past; this way, the state at the beginning of the sync operation is well known and sound. When this condition is not met (for instance, the mobile device has been reset and lost the timestamp of the last synchronization), a full synchronization must be performed. In a full synchronization, the client sends its entire database to the server, which compares it with its local database and returns the modifications that must be applied to be up-to-date again.

Both fast and full synchronization modes can be performed in one of the following manners:

  • Client-to-server: The server updates its database with client modifications, but sends no server-side modifications

  • Server-to-client: The client updates its database with server modifications, but sends no client-side modifications

  • Two-way: The client and server exchange their modifications and both databases are updated accordingly

Extending Funambol

The Funambol platform can be extended in many areas to integrate Funambol with existing systems and environments. The most common integration use cases and the Funambol modules involved are:

  • Officer: Integrating with an external authentication and authorization service

  • SyncSource: Integrating with an external datasource to address client specific issues

  • Synclet: Adding pre or postprocessing to a SyncML message

  • Admin WS: Integrating with an external management tool

These are illustrated in the following diagram:

Extending Funambol

Funambol extensions are distributed and deployed as Funambol modules. This section describes the structure of a Funambol module, while the following sections describe each of these listed scenarios.

A Funambol module represents the means by which developers can extend the Funambol server. A module is a packaged set of files containing Java classes, installation scripts, configuration files, initialization SQL scripts, components, and so on, used by the installation procedure to embed extensions into the server core.

For more information on how to install Funambol modules, see the Funambol Installation and Administration Guide.

Building a Funambol module

A Funambol module is a ZIP package named using the following convention:

<module-name>-<major-version>.<minor-version>.s4j

Here<module-name> is the name of the module without spaces and using lowercase characters only, and<major/minor-version> are the major and minor version numbers. A new version of a module with a minor version number change must be backward compatible, while changes in the major version number imply that a migration may be required.

The package must have the structure illustrated in the following diagram:

Building a Funambol module

In the previous diagram, entries ending with a '/' represent directories and filenames in italic are given as examples (in a real package they will be replaced with real filenames).

The module classes are packaged in a main JAR file called<modulename>.jar.

Configuration files are stored under the package directory config, creating subdirectories as needed.

Note

Even if it is not mandatory, usually SyncSource instance configuration files are stored under a subtree in the form<module-id>/<connector-id>/<sourcetype-id>, which is the convention used by the Funambol Administration Tool when creating a new SyncSource instance.

The directory install contains install.xml, an Apache Ant script that is called when the module is installed; this is the hook where a module developer can insert module specific installation tasks. Installation specific files can be organized in subdirectories under install.

If the module requires a custom database schema, the scripts to create, drop, and initialize the database are stored under the sql/<database> directory, where<database> is the name of the DBMS as listed in the install.properties file.

Finally, the exclude directory is used to store files that will be temporarily used by the installation procedure, but will not be (automatically) copied. These can be used by the module installation script for any purpose.

Modules, connectors, listeners, and SyncSource types

As mentioned, a module is a container for anything related to one or more server extensions, which are used by the engine to communicate and integrate with external systems. These extensions are usually specific with backend to be integrated. A specific case of such an extension is when the main purpose is to connect to an external datasource and in this case the module is called a connector. In other words, a connector is an extension of the server, intended to support the synchronization of a particular datasource.

To access the datasource, the connector must provide a SyncSource type. A SyncSource type represents the template from which an instance of a SyncSource can be created. For example, the FileSystemSyncSource type made available by Funambol is the means used by the server to synchronize data stored in the file system. However, it does not represent a particular directory to synchronize. In order to synchronize a specific directory (for instance /data/contacts) a real SyncSource instance must be created and configured with the desired directory. You can think of a SyncSource type as a class and of a SyncSource as an instance.

An additional (but optional) component that a connector can provide is called listener. This component is in charge of detecting changes in the backend so that the server can trigger a device to synchronize the changes.

Note

Funambol provides a module called foundation that contains basic functionality, libraries, and classes required by all custom modules. This module must not be removed from any Funambol installation.

Registering modules, connectors, and SyncSource types

Modules, connectors, and SyncSource types are registered by filling the following database tables:

  • fnbl_module for module information

  • fnbl_connector for connector information

  • fnbl_sync_source_type for SyncSource type information

  • fnbl_connector_source_type for connector-SyncSource type associations

  • fnbl_module_connector for module-connector association

Note

The last two tables are used to create the hierarchy module-connector-SyncSource type that can be seen in the Funambol Administration Tool.

Let's consider the registration of the foundation module. When Funambol is installed, the foundation module is also installed. It brings a connector called FunambolFoundationConnector which, in turn, contains the SyncSource types PIM Contact SyncSource, PIM Calendar SyncSource, FileSystem SyncSource, and SIF SyncSource as shown in the following screenshot:

Registering modules, connectors, and SyncSource typesFunambolfoundation module

This hierarchy is obtained with the following SQL commands:

  1. Module registration:

    insert into fnbl_module (id, name, description)
    values('foundation','foundation','Foundation');
    
  2. SyncConnector registration:

    insert into fnbl_connector(id, name, description)
    values('foundation','FunambolFoundationConnector', 'Funambol Foundation Connector');
    
  3. The Foundation Connector belongs to the foundation module:

    insert into fnbl_module_connector(module, connector)
    values('foundation','foundation');
    
  4. The SyncSource Type registration:

    insert into fnbl_sync_source_type(id, description, class, admin_class)
    values('contact-foundation','PIM Contact SyncSource', 'com.funambol.foundation.engine.source. PIMContactSyncSource', 'com.funambol.foundation.admin. PIMContactSyncSourceConfigPanel');
    insert into fnbl_sync_source_type(id, description, class,admin_class)
    values('calendar-foundation','PIM Calendar SyncSource', 'com.funambol.foundation.engine.source. PIMCalendarSyncSource', 'com.funambol.foundation.admin. PIMCalendarSyncSourceConfigPanel');
    insert into fnbl_sync_source_type(id, description, class, admin_class)
    values('fs-foundation','FileSystem SyncSource', 'com.funambol.foundation.engine.source. FileSystemSyncSource', 'com.funambol.foundation.admin. FileSystemSyncSourceConfigPanel');
    insert into fnbl_sync_source_type(id, description, class, admin_class)
    values('sif-fs-foundation','SIF SyncSource','com.funambol.foundation.engine.source.SIFSyncSource','com.funambol.foundation.admin.SIFSyncSourceConfigPanel');
    
  5. Finally, the SyncSource type belongs to the Foundation Connector:

    insert into fnbl_connector_source_type(connector, sourcetype)
    values('foundation','contact-foundation');
    insert into fnbl_connector_source_type(connector, sourcetype)
    values('foundation','calendar-foundation');
    insert into fnbl_connector_source_type(connector, sourcetype)
    values('foundation','fs-foundation');
    insert into fnbl_connector_source_type(connector, sourcetype)
    values('foundation','sif-fs-foundation');
    

    Note

    Two classes are specified for each SyncSource type registration—The class (for example, com.funambol.foundation.engine.source.FileSystemSyncSource) that actually implements the SyncSource interface, and the admin_class that is used to create a new SyncSource instance and to configure it in the Funambol Administration Tool.

In the following section, we will see how these two classes are developed.

Note

In this guide, SyncSource and SyncSource Type are often treated as synonyms, even if they are in the template-instance relationship seen before.

Getting started on connector development

This section describes how to create a connector that extends the functionality of the Funambol Data Synchronization Service.

In this section we will use the following terms and concepts:

  • Module: A module is a container for anything related to one or more server extensions, which are used by the engine to integrate with external systems.

  • Connector: A connector is a particular type of module, whose primary purpose is to connect to an external datasource. In other words, a connector is an extension of the DS service intended to support the synchronization of a particular datasource.

  • SyncSource: This is a key component of a connector that defines the way a set of data is made accessible to the Funambol Data Synchronization Service for synchronization. A SyncSource type represents the template from which an instance of a SyncSource can be created.

  • Synclet: A preprocessing or postprocessing unit that can process a SyncML message before it gets into the synchronization engine or just after it is going out from it.

This chapter will guide the developer through the development, packaging, installation, and testing of a module. The module contains a simple SyncSource and Synclet, which will just produce some logging. In this way, the developer can easily see the flow of calls to the SyncSource API during a synchronization.

Note

After becoming familiar with the tutorial, it is recommended that you inspect some real-world examples of connectors such as the OpenXchange connector (https://funamboloxconnector.forge.funambol.org) or the Exchange connector (https://exchange-connector.forge.funambol.org).

Getting started

The following connector development quick-start section assumes a working knowledge of Java, Maven, and SQL.

To follow this section you will need:

  • Funambol Data Synchronization Service installed and running

  • Funambol Software Development Kit

  • Java 2 SDK version 1.5.x or above

  • Apache Maven (see http://maven.apache.org)

  • Optionally, you may want to download a Maven plugin for your preferred IDE (see http://mevenide.codehaus.org)

Note

To download the Funambol SDK, go to https://www.forge.funambol.org/download and click on Funambol SDK in the Get started with Funambol section.

After downloading the software, install it in a directory of choice. In the following section we will use the below directory conventions:

  • $FUNAMBOL_HOME: This is the directory where the bundle has been installed (for example, /opt/Funambol)

  • $FUNAMBOL_SDK_HOME: This is the directory where the Funambol SDK has been installed (for example, /opt/Funambol/tools/sdk)

  • $JAVA_HOME: This is the directory where Java is installed (for example, /opt/jdk1.5.0_10)

  • $MAVEN_HOME: This is the directory where Apache Maven is installed (for example, /opt/apache-maven-2.0.8)

  • $USER_HOME: This is the home directory of the operating system you are using (for example, /home/ste, c:Usersste)

Note

Basic knowledge of Apache Maven, its terminology, and principles is assumed, as the following sections use terms from the Maven world without explaining them in detail. For more information refer to http://maven.apache.org/guides/getting-started/index.html.

After the installation, Maven should be configured to point to the Funambol public Maven repository (m2.funambol.org/repositories). To do so, copy the file $FUNAMBOL_SDK_HOME/docs/settings.xml under $USER_HOME/.m2.

Overview

The following sections are a guide on how to develop the sample module. This can be done using the following steps:

  1. Create the connector project.

  2. Install the module.

  3. Create a SyncSource instance.

  4. Test the module with a SyncML client.

Create the connector project

The easiest way to create a connector project is by running the following Maven command:

mvn archetype:generate -DarchetypeGroupId=funambol
connector project, creatingMaven command, using-DarchetypeArtifactId=funambol-module-archetype -DarchetypeVersion=7.1.0
-DgroupId=acme -DartifactId=acmeconnector
-DarchetypeRepository=http://m2.funambol.org/repositories/artifacts
-Dversion=1.0.0

When prompted for an answer, type Y.

This command will download and create a skeleton application ready to be built, which contains:

  • A normal SyncSource

  • A mergeable SyncSource

  • An input/output synclet

  • All configuration and SQL files

All of these will be generated in a Maven project located in a directory named acmeconnector. The content of the directory is illustrated in the following screenshot:

Create the connector project

The following table explains the function of each file:

File

Description

LICENSE.txt

AGPL license file

pom.xml

Maven project file for the connector

src/main/config/com/funambol/server/engine/pipeline/input/000.000.mysynclet.xml

Sample input synclet configuration

src/main/config/com/funambol/server/engine/pipeline/output/000.000.mysynclet.xml

Sample output synclet configuration

src/main/external/readme.txt

Readme for the content of this directory

src/main/install/install.xml

Module installation file

src/main/java/acme/MyMergeableSyncSource.java

Sample mergeable SyncSource

src/main/java/acme/ MySynclet.java

Sample synclet

src/main/java/acme/MySyncSource.java

Sample SyncSource

src/main/java/acme/MySyncSourceAdminPanel.java

Sample administration panel for both MySyncSource and MyMergeableSyncSource

src/main/sql/*/ create_schema.sql

SQL scrip to create the database tables required by the module

src/main/sql/*/drop_schema.sql

SQL scrip to drop the database tables required by the module

src/main/sql/*/init_schema.sql

SQL scrip to initialize the database tables required by the module

Note

Take a moment to explore and open each file to become familiar with its contents.

MyMergeableSyncSource type

As seen earlier, the SyncSource type is the primary component of the connector. The source code created by the archetype is very simple. It only writes some logging information to trace its execution. However in a real project this is where the code necessary to integrate an external datasource would go.

MyMergeableSyncSource inherits most of its behavior from MySyncSource. Open this file in an editor or in your IDE and go through it. MySyncSource defines three properties that can be set via the Funambol Administration Tool. These are myString, myInt, and myMap. Getter and setter methods to get and set those properties are provided. Also, note that the class implements all methods of the SyncSource interface by writing a log entry. Each method also has a description of what it does and what the developer should add.

MySynclet

In addition to the SyncSource types described earlier, the archetype project also contains a sample input and output synclet—MySynclet. Open it in an editor or in your IDE and go through it.

Note

If you don't need to write a synclet, you can skip this section.

The first thing to note is that it implements both an input and an output synclet, which means that the synclet will be called for both incoming and outgoing messages. The synclet is very simple; it just logs the message in the funambol.myconnector logger.

MySyncSourceAdminPanel

The goal of this section is to create a new SyncSource based on MyMergeableSyncSource and to configure it via the Funambol Administration Tool. This is possible because of the class MySyncSourceAdminPanel. Open it with an editor or in your IDE and go through it.

MySyncSourceAdminPanel inherits SourceManagementPanel, which is a class of the Admin framework. SourceManagementPanel is a java.swing.JPanel, therefore it has all the methods of a swing panel. The init() method creates all widgets that we want to display in the Funambol Administration Tool and adds them to the panel. These widgets are as follows:

  • Source name

  • Data types supported (e.g. text/vcard)

  • Data type versions supported (e.g. 2.1)

  • Source URI

  • myString

  • myInt

  • myMap entry

In addition, it adds a JButton to the panel to save the values of an existing SyncSource or to add a newly created SyncSource. An important aspect to note is that this is where the panel interacts with the Funambol Administration Tool to save the changes to the server. The following code performs this task:

confirmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event ) {
try {
validateValues();
getValues();
if (getState() == STATE_INSERT)
{
SyncSourceAdminPanel.this.actionPerformed(
newActionEvent(MySyncSourceAdminPanel.this,
ACTION_EVENT_INSERT,
event.getActionCommand()));
} else {
MySyncSourceAdminPanel.this.actionPerformed(
new ActionEvent(MySyncSourceAdminPanel.this,
ACTION_EVENT_UPDATE,
event.getActionCommand()));
}
} catch (Exception e)
{
notifyError(new AdminException(e.getMessage()));
}
}
});

The key is that, when needed, the method actionPerformed() of the base class is called with a proper event.

Another important method is updateForm() where the value of the SyncSource instance is displayed in proper fields. Again this method is called by the Funambol Administration Tool when an existing instance must be displayed.

Creating and installing the connector package

To package the created project into a Funambol module, go in the project directory and type:

mvn package

A typical output will be as follows:

[INFO] Scanning for projects...
[INFO] --------------------------------------------------
[INFO] Building acme acmeconnector Module
[INFO] task-segment: [package]
[INFO] --------------------------------------------------
[INFO] artifact org.apache.maven.plugins:maven-resources-plugin: checking for updates from artifacts
[INFO] artifact org.apache.maven.plugins:maven-resources-plugin: checking for updates from snapshots
[INFO] artifact org.apache.maven.plugins:maven-compiler-plugin: checking for updates from artifacts
[INFO] artifact org.apache.maven.plugins:maven-compiler-plugin: checking for updates from snapshots
[INFO] artifact org.apache.maven.plugins:maven-surefire-plugin: checking for updates from artifacts
[INFO] artifact org.apache.maven.plugins:maven-surefire-plugin: checking for updates from snapshots
[INFO] artifact org.apache.maven.plugins:maven-jar-plugin: checking for updates from artifacts
[INFO] artifact org.apache.maven.plugins:maven-jar-plugin: checking for updates from snapshots
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Compiling 4 source files to /Users/ste/Projects/acmeconnector/target/classes
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] No sources to compile
[INFO] [surefire:test]
[INFO] No tests to run.
[INFO] [jar:jar]
[INFO] Building jar: /Users/ste/Projects/acmeconnector/target/acmeconnector-1.0-SNAPSHOT.jar
[INFO] [funambol:s4j]
[INFO] Exploding Funambol packaging...
[INFO] Assembling Funambol packaging acmeconnector in /Users/ste/Projects/acmeconnector/target/acmeconnector-1.0-SNAPSHOT
[INFO] Including license file /Users/ste/Projects/acmeconnector/LICENSE.txt
[INFO]
[INFO] Including artifacts:
[INFO] -------------------
[INFO] x funambol:server-framework:jar:8.0.3-SNAPSHOT:compile
[INFO] x funambol:core-framework:jar:6.5.4:compile
[INFO] x funambol:ext:jar:6.5.2:compile
[INFO] o org.jibx:jibx-run:jar:1.1.2fun:compile
[INFO] o xpp3:xpp3:jar:1.1.2a-fun:compile
[INFO] o commons-lang:commons-lang:jar:2.3:compile
[INFO] o funambol:admin-framework:jar:6.5.2:compile
[INFO]
[INFO] Excluded artifacts:
[INFO] ------------------
[INFO]
[INFO] Including jar files...
[INFO] basedir: /Users/ste/Projects/acmeconnector
[INFO] srcDir: /Users/ste/Projects/acmeconnector/src/main
[INFO] sqlDirectory: /Users/ste/Projects/acmeconnector/target/acmeconnector-1.0-SNAPSHOT/sql
[INFO] wsddDirectory: /Users/ste/Projects/acmeconnector/target/acmeconnector-1.0-SNAPSHOT/wsdd
[INFO] No config files...
[INFO] No exclude files...
[INFO] Including install files...
[INFO] Including sql files...
[INFO] No wsdd files...
[INFO]
[INFO] Generating Funambol packaging /Users/ste/Projects/acmeconnector/target/acmeconnector-1.0-SNAPSHOT.s4j
[INFO] Building jar: /Users/ste/Projects/acmeconnector/target/acmeconnector-1.0-SNAPSHOT.s4j
[INFO] --------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] --------------------------------------------------
[INFO] Total time: 12 seconds
[INFO] Finished at: Sat May 17 15:42:08 CEST 2008
[INFO] Final Memory: 9M/16M
[INFO] -------------------------------------------------------------

Note

The final message Generating Funambol packaging /Users/ste/Projects/acmeconnector/target/acmeconnector-1.0-SNAPSHOT.s4j tells where the package is created.

To install the newly created module into the server, copy acmeconnector-1.0-SNAPSHOT.s4j into $FUNAMBOL_HOME/ds-server/modules and follow the steps detailed next:

  1. Make sure Funambol is up and running.

  2. Using a text editor, open the $FUNAMBOL_HOME/ds-server/install.properties file.

  3. Find the line that begins with modules-to-install= in the Module definitions section. This line specifies, in a comma-separated list, the modules to install during installation.

  4. Add acmeconnector-1.0-SNAPSHOT to the comma-separated list (note that you do not have to specify the .s4j file extension).

  5. Save and close install.properties.

  6. Open a command window and run the server installation script by typing:

    • on Windows:

      cd $FUNAMBOL_HOME/ds-server
      bininstall-modules
      
    • on Unix/Linux:

      cd $FUNAMBOL_HOME/ds-server
      bin/install-modules
      
  7. Answer all questions about recreating the modules DB schema when prompted. Type Y when asked to install the database for the new module and N for all others.

    [echo] Funambol Data Synchronization Server will be installed on the Tomcat 5.5.x application server
    [echo] Undeploying funambol...
    [echo] Pre installation for modules foundation- 8.0.1,acmeconnector-1.0-SNAPSHOT
    [echo] foundation-8.0.1 pre-installation...
    [echo] foundation-8.0.1 pre-installation successfully completed
    [echo] acmeconnector-1.0-SNAPSHOT pre-installation...
    [echo] acmeconnector-1.0-SNAPSHOT pre-installation successfully completed
    [echo] Copying configuration files
    [echo] Post installation for modules foundation- 8.0.1,acmeconnector-1.0-SNAPSHOT
    [echo] has.install: true
    [echo] Starting custom installation...
    [echo] Foundation Installation
    [echo] Foundation installation successfully completed
    [echo] foundation-8.0.1 installation...
    [echo] Database installation for module foundation- 8.0.1 on hypersonic (/opt/Funambol/ds-server)
    [iterate] The Funambol Data Synchronization Server installation program can now create
    [iterate] the database required by the module foundation-8.0.1 (if any is needed).
    [iterate] You can skip this step if you have already a valid database created
    [iterate] or the module does not require a database.
    [iterate] If you choose 'y' your existing data will be deleted.
    [iterate] Do you want to recreate the database?
    [iterate] (y,n)
    n
    [...]
    [echo] foundation-8.0.1 installation successfully completed
    [echo] has.install: true
    [echo] Starting custom installation...
    [echo] acmeconnector installation
    [echo] acmeconnector installation successfully completed
    [echo] acmeconnector-1.0-SNAPSHOT installation...
    [echo] Database installation for module acmeconnector-1.0-SNAPSHOT on hypersonic (/opt/Funambol/ds-server)
    [iterate] The Funambol Data Synchronization Server installation program can now create
    [iterate] the database required by the module acmeconnector-1.0-SNAPSHOT (if any is needed).
    [iterate] You can skip this step if you have already a valid database created
    [iterate] or the module does not require a database.
    [iterate] If you choose 'y' your existing data will be deleted.
    [iterate] Do you want to recreate the database?
    [iterate] (y,n)y
    [echo] acmeconnector-1.0-SNAPSHOT installation
    successfully completed
    [war] Warning: selected war files include a WEB-
    INF/web.xml which will be ignored (please use webxml
    attribute to war task)
    [echo] Remove output dir
    BUILD SUCCESSFUL
    Total time: 12 seconds
    
  8. Restart the Data Synchronization Service.

The new connector is now installed.

Creating a SyncSource

Now that the acmeconnector is installed, it is displayed in the Funambol Administration Tool, under the Modules section, as shown in the following screenshot:

Creating a SyncSource

Once the new SyncSource type is installed on the server, a new instance of the SyncSource can be created and configured so that it is available to the clients. This is done by means of the Funambol Administration Tool. Right-click the MyMergeableSyncSource node and select New from the context menu that pops up. The form illustrated on the right side of the previous screenshot will appear.

This window is used to specify configuration values. Insert the following values and click Add:

Source URI: acme
Name: Acme
Supported type: text/plain
Supported version: 1.0
MyString: acme connector!
MyInt: 10
MyMap entry: <acme, connector>

Testing the connector

To test the Acme connector, a simple command line client will be used. This is distributed in the Funambol SDK under $FUNAMBOL_SDK_HOME/plug-ins/cl.

Before using it, the command line client must be configured to access the SyncSource created earlier. Edit the file config/spds/sources/briefcase.properties and set the following values:

name=acme
sourceClass=com.funambol.syncclient.spds.source.FileSystemSyncSource
sourceDirectory=db/briefcase
type=text/plain
sync=two-way
encode=true
sourceURI=acme

The command line tool is a simple client that synchronizes the content of a given directory. This is the one specified by the sourceDirectory parameter. In the case of Acme connector, however, we are not interested in the data transfer, but more interested in learning the calls executed in the connector SyncSource.

To launch the client, run the command $FUNAMBOL_SDK_HOMEplug-insclinrun.cmd on Windows (or $FUNAMBOL_SDK_HOME/plug-ins/cl/run.sh if using Linux).

An output similar to the following will be displayed:

Funambol Command Line Tool ver. 8.0.1
--------------------------
2008-04-17 16:28:10:969 - # SyncClient API J2SE Log
16:28:10:970 [INFO] - Initializing
16:28:10:973 [INFO] - Sending initialization commands
16:28:11:716 [INFO] - The server alert code for acme is 201
6:28:11:718 [INFO] - Synchronizing acme
16:28:11:745 [INFO] - exchange modifications started
16:28:11:746 [INFO] - Preparing slow sync for acme
16:28:11:747 [INFO] - Detected 0 items
16:28:11:748 [INFO] - Sending modifications
16:28:11:837 [INFO] - Returned 0 new items, 0 updated items, 0 deleted items for acme
16:28:11:838 [INFO] - Mapping started
16:28:11:841 [INFO] - Sending mapping
16:28:11:853 [INFO] - Sending mapping
16:28:11:874 [INFO] - Mapping done
16:28:11:874 [INFO] - Synchronization done

The server log shows the Acme connector at work. After filtering out the lines that are not of interest for our connector, the log entries will be similar to the following text:

[2008-05-17 16:31:56,656] [funambol.myconnector] [INFO] [399F31F06404433DE69A05F71D562ACD] [sc-api-j2se] [guest] [] Initializing acme.MyMergeableSyncSource
connector developmenttesting[2008-05-17 16:31:56,657] [funambol.myconnector] [INFO] [399F31F06404433DE69A05F71D562ACD] [sc-api-j2se] [guest] [] myString: acme connector!
[2008-05-17 16:31:56,657] [funambol.myconnector] [INFO] [399F31F06404433DE69A05F71D562ACD] [sc-api-j2se] [guest] [] myInt: 10
[2008-05-17 16:31:56,657] [funambol.myconnector] [INFO] [399F31F06404433DE69A05F71D562ACD] [sc-api-j2se] [guest] [] myMap: {acme=connector}

[2008-05-17 16:31:56,703] [funambol.myconnector] [INFO] [399F31F06404433DE69A05F71D562ACD] [sc-api-j2se] [guest] [acme] Starting synchronization: com.funambol.framework.engine.source.SyncContext@e85079
[2008-05-17 16:31:56,703] [funambol.myconnector] [INFO] [399F31F06404433DE69A05F71D562ACD] [sc-api-j2se] [guest] [acme] getNewSyncItemKeys()
[2008-05-17 16:31:56,703] [funambol.myconnector] [INFO] [399F31F06404433DE69A05F71D562ACD] [sc-api-j2se] [guest] [acme] getUpdatedSyncItemKeys()
[2008-05-17 16:31:56,703] [funambol.myconnector] [INFO] [399F31F06404433DE69A05F71D562ACD] [sc-api-j2se] [guest] [acme] getDeletedSyncItemKeys()
[2008-05-17 16:31:56,703] [funambol.myconnector] [INFO] [399F31F06404433DE69A05F71D562ACD] [sc-api-j2se] [guest] [acme] Committing synchronization
[2008-05-17 16:31:56,782] [funambol.myconnector] [INFO] [399F31F06404433DE69A05F71D562ACD] [sc-api-j2se] [guest] [acme] Ending synchronization

Note

Note: The first entries of the log show the values inserted earlier in the administration panel, which means that the SyncSource configuration was properly picked up.

Similarly, the server log also shows the effect of MySynclet. Each SyncML message has been logged; for example the first input message is something like the following text:

[2008-05-17 16:59:28,576] [funambol.myconnector] [INFO] [FF4B335BA02F0581DAFF016319EDD263] [] [] []
[2008-05-17 16:59:28,576] [funambol.myconnector] [INFO] [FF4B335BA02F0581DAFF016319EDD263] [] [] [] Input message[2008-05-17 16:59:28,576] [funambol.myconnector] [INFO] [FF4B335BA02F0581DAFF016319EDD263] [] [] [] [2008-05-17 16:59:28,585] [funambol.myconnector] [INFO] [FF4B335BA02F0581DAFF016319EDD263] [] [] [] <?xml version="1.0" encoding="UTF-8"?> <SyncML><SyncHdr><VerDTD>1.1</VerDTD><VerProto> SyncML/1.1</VerProto><SessionID>12345678</SessionID><MsgID>1</MsgID><Target><LocURI>http://localhost:8080/funambol/ds</LocURI></Target> <Source><LocURI>sc-api-j2se</LocURI></Source> <Cred><Meta><Type>syncml:auth-basic</Type></Meta> <Data>Z3Vlc3Q6Z3Vlc3Q=</Data></Cred><Meta><MaxMsgSize>250000 </MaxMsgSize><MaxObjSize>4000000</MaxObjSize></Meta></SyncHdr> <SyncBody><Alert><CmdID>1</CmdID><Data>200</Data><Item><Target> <LocURI>acme</LocURI></Target><Source><LocURI>acme</LocURI></Source> <Meta><Anchor><Last>1211034716596</Last><Next>1211036368401</Next> </Anchor></Meta></Item></Alert><Final/></SyncBody></SyncML>[2008-05-17 16:59:28,585] [funambol.myconnector] [INFO] [FF4B335BA02F0581DAFF016319EDD263] [] [] [] -------------------------------------------------------------

The last output message is something like the following:

[2008-05-17 16:59:28,876] [funambol.myconnector] [INFO] [FF4B335BA02F0581DAFF016319EDD263] [sc-api-j2se] [guest] []
[2008-05-17 16:59:28,877] [funambol.myconnector] [INFO] [FF4B335BA02F0581DAFF016319EDD263] [sc-api-j2se] [guest] []
Output message[2008-05-17 16:59:28,877] [funambol.myconnector] [INFO] [FF4B335BA02F0581DAFF016319EDD263] [sc-api-j2se] [guest] []
[2008-05-17 16:59:28,877] [funambol.myconnector] [INFO] [FF4B335BA02F0581DAFF016319EDD263] [sc-api-j2se] [guest] []
<?xml version="1.0" encoding="UTF-8"?> <SyncML><SyncHdr><VerDTD>1.1</VerDTD><VerProto>SyncML/1.1</VerProto> <SessionID>12345678</SessionID><MsgID>5</MsgID><Target><LocURI>sc-api-j2se</LocURI></Target><Source><LocURI> http://localhost:8080/funambol/ds</LocURI></Source> <RespURI>http://localhost:8080/funambol/ds;jsessionid=FF4B335BA02F0581DAFF016319EDD263</RespURI></SyncHdr><SyncBody><Status><CmdID>1 </CmdID><MsgRef>5</MsgRef><CmdRef>0</CmdRef><Cmd>SyncHdr</Cmd><TargetRef>http://localhost:8080/funambol/ds</TargetRef><SourceRef>sc-api-j2se</SourceRef><Data>200</Data></Status><Final/></SyncBody></SyncML>[2008-05-17 16:59:28,877] [funambol.myconnector] [INFO] [FF4B335BA02F0581DAFF016319EDD263] [sc-api-j2se] [guest] [] ---------------
 ----------------------------------------------

If you have reached this point, you have successfully developed and deployed a Funambol connector. Congratulations! You can now further extend the acmeconnector project or start your own.

Debugging

When developing a connector, it can be very helpful to to use a debugger to inspect the behavior of the connector to discover and fix bugs. The best way to do this is to use the remote debugging capabilities provided by the Java Virtual Machine (JVM). To do so, follow these steps:

  1. Edit the file $FUNAMBOL_HOME/bin/funambol-server uncommenting the JPDA_OPTS line, which you can easily find if you search for "debug". This will start Funambol, enabling it for remote debugging.

  2. Connect to the running JVM. If you use Eclipse, you can create a debug profile to attach to Funambol. Note that the debug port given in the JPDA_OPTS line is 8787, not eclipse's default port, (8000), so either change the JDPA_OPTS or the Eclipse port. NetBeans supports remote debugging too. Click on the Debug menu item and then select Attach Debugger.

  3. Now you can start a sync session and stop at breakpoints.

Summary

This chapter helps developers who want to extend the Funambol DS Service to integrate with their own backend datasources. This chapter presented some key concepts of the synchronization process, which provided us with the background information needed to understand some of the details of the Funambol API and framework. It also showed that developing a connector can be pretty straightforward. By following the steps presented in this chapter, a new simple connector can be created and deployed. This is only a starting point, but it allows developers to see the overall synchronization flow, from a client making a synchronization request, to the connector code.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.176.194