Home  >  

AIR Data Synchronization via LiveCycle Data Services ES 2.6

Author photo
AddThis Social Bookmark Button

I have long said offline applications are one of Adobe AIR's greatest abilities/features. It isn't numero uno but, in my book, it is definitely in my top 5 feature list. Doing better offline sync with database data was made easier with the addition of SQLite into the AIR runtime versus using XML, shared objects, or some of mechanism. Now Adobe has taken it one step further and made it so simple we are going to create a complete offline/online application in 30 minutes or less.

With LiveCycle Data Services ES 2.6 ("LCDS"), Adobe has added native caching for AIR and the Flash Player. This is an amazing advancement due to the small amount of code required to complete offline synchronization compared to a custom solution. The goal of this article is to provide a start to finish guide to building an AIR application with offline data synchronization from LCDS. I am a tactile learner and I like to write and present this way so instead of chatting...let's code!

Note: As of this article publication date, LCDS is presently in a Beta 2 phase so the following code and screenshots could be different in the final release.

Prerequisites: * Adobe Flex Builder 3 - http://www.adobe.com/go/flex
* Adobe AIR runtime - http://www.adobe.com/go/air
* LiveCycle Data Services ES 2.6 Beta 2 installer - http://labs.adobe.com/technologies/livecycle_dataservices2_6/
* Basic knowledge of Adobe AIR, Flex, and LiveCycle Data Services ES

Installing LCDS

The first step to building your application is to download and install LCDS. Download LCDS from Adobe Labs and start the installer. After the installer initializes you will come to the Welcome screen. Click Next. The next two screens (License Agreement and Serial Number) are normal screens as well so click Next through these. If you have a license, feel free to enter it in Step 3. Leaving the serial number blank will install the Express version, which is what we will use. Step 4, Installation Location, is completely up to you. The default is "c:\lcds" but I prefer putting all server software in a base "servers" folder so I use "c:\servers\lcds" (with a potential version number on the "lcds" folder). Step 5, Installation Options, is pertaining to your deployment. If you select "LiveCycle Data Services with Tomcat" an instance of Tomcat will be included in the install. If you do not have JRun, Tomcat, or another Java application server available, select this option. If you do have another Java application server and want to install LCDS there, use the "LiveCycle Data Services J2EE web application" option. For the purposes of this article, we will use "LiveCycle Data Services with Tomcat". On Step 6, Pre-Installation Summary, all of your selected options are listed. This is the last step before installing so double check your install path, etc before clicking Install.

Once you are comfortable with your settings and have clicked Install, the install will begin, complete, and provide you with Step 8, Installation Complete (see Figure 1). You can uncheck "Launch readme file?", unless you actually read "readme" files, and click Done. We are ready to start LCDS.

InstallerComplete.jpg
Figure 1 - Last step in install process.

Starting LCDS

Figure 1 shows the url to the "lcds-samples" web application (http://localhost:8400/lcds-samples). Before you go there, we have to start LCDS and the sample database. To do so run the following batch files, in order: [LCDS ES install]\sampledb\startdb.bat, [LCDS ES install]\tomcat\bin\startup.bat. "startdb.bat" will open a command prompt window and start the HSQL sample databases (see Figure 2). "startup.bat" will start an instance of Tomcat (see Figure 3) on port 8400. You can minimize both windows as we won't need them anymore. Do not close them though. If you close them they will stop running.

Note: Keep in mind this is for a development environment. On a production machine LCDS would run inside your production Java application server, which would already be started.

StartLCDSDatabase.jpg
Figure 2 - Command Prompt for "startdb.bat" (sample databases).
TomcatStartup.jpg
Figure 3 - Command Prompt for "startup.bat" (Tomcat).

LCDS is now alive and well, barring no error messages in Figure 3. Open your browser and browse to: http://localhost:8400/. The LCDS welcome page has links to the new, and may I add very helpful, Console Application (see Figure 4), the Samples Application (a place to view some of the things you can accomplish with LCDS), and a Template Application (useful for starting a new application). Feel free to browse the links for a bit before moving on. I highly suggest looking at the Samples Application. You can really get a solid view of what LCDS offers.

LCDSConsoleApp.jpg
Figure 4 - The new Console Application in LCDS.

LCDS is installed, started, and ready to be used. It is time to write our application. Instead of focusing on the backend Java code we're going to use the sample CRM backend (http://localhost:8400/lcds-samples/#crm) but build our own application.

Setting up the Project

The setup process is the same as any normal AIR project. Open Flex Builder 3 and go to File->New->Flex Project. The initial screen will ask you for the project type (Web or Desktop), choose Desktop, give the project a name of your liking, and click Next. At this point you can click Finish. The AIR project has been created and we are ready to code.

Before we start writing code, we do need to add a few SWC files. Copy the following files in your projects /lib directory: [LCDS ES install]\tomcat\webapps\lcds\WEB-INF\flex\locale\en_US\fds_rb.swc, [LCDS ES install]\tomcat\webapps\lcds\WEB-INF\flex\libs\fds.swc, and [LCDS ES install]\tomcat\webapps\lcds\WEB-INF\flex\libs\air\airfds.swc. These files have the classes necessary to integrate with LCDS and "airfds.swc" provides the sweet Adobe AIR support for local caching.

Note: If you are in a different locale, substitute "en_US" with whatever locale folder contains the fds_rb.swc.

Note: The swc’s could have been added in the project creation step from the last screen in the wizard.

The Project

If you haven't felt the proper level of geekdom yet, stay tuned. We are about to build a desktop application capable of caching our content offline and manage online synchronization in under 130 lines of code! Oh, imports and some comments are included in the 130 as well. We will examine each code block individually before tie everything together.

User Interface

We have an empty project with three swc files included. Our first step is to create the user interface (UI). Our UI will be a mix between the CRM Mini and the full CRM sample applications. The focus of the application is the data so we won't worry about prettying up the visuals.

<mx:VBox width="100%" height="100%">
	<mx:HBox>
		<mx:LinkButton label="+" click="showNewCompanyWindow()" />
		<mx:LinkButton label="-" enabled="{companiesGrid.selectedIndex >= 0}" click="deleteCompany()" />
	</mx:HBox>
	<mx:DataGrid id="companiesGrid" width="100%" height="100%" dataProvider="{companies}" />
</mx:VBox> 
Listing 1 - User Interface (Note: Full source download link at end of article)

Listing 1 is the core UI. The first row, HBox, contains the “+” and “-“ LinkButtons with a DataGrid in the second row of the VBox. This is as visual as we will get for this application (see Figure 5). Ignore the click events and the dataProvider for companiesGrid for now. Keep in mind we will tie this all together as we move on.

Note: Take a look at the full CRM to see a much fuller UI for managing the data.

UI.jpg
Figure 5 - Our simple UI in Flex Builder Design View.

Application Initialization

The application initialization is the core piece to our app (see Listing 2) and is where we setup our connection to LCDS. Initially we create three variables. contacts is the holder our DataService will fill. companyDS is the beast of the party. It is the DataService and will handle all of the communication between our application and the server. monitor is a URLMonitor we will use to know when the LCDS server is online or offline. There is a lot more to finding out if a user is online or offline though. For a true offline/online experience you want to listen for a NETWORK_CHANGE event as well as use a monitor but we're keeping it simple.

We are listening for the applicationComplete event, on the WindowedApplication, to initialize our application in the init() function. Our first order of business is to create the DataService and set the destination to "crm-company". The next line sets the cacheID. cacheID is completely up to you, must be unique, is required, and can be changed on the fly. Although for this application we don't do anything with the events, the event listeners are added to keep runtime errors away and for monitoring in debug mode. You can use these events to handle faults and message events from the server as wella s listen for data conflict events.

Note: When the cacheID is changed on the fly, the cache is cleared. The in-memory data is still there for your manipulation though.

In order to connect to LCDS you have to specify the url to the server and the connection type. For our use we're going to connect using RTMP to our local server (localhost) over port 2037, the default port. To do so we create an RTMPChannel, a ChannelSet, add the RTMPChannel to the ChannelSet, and set the companyDS.channelSet to our custom ChannelSet. At this point we are ready to connect to LCDS. The last step in our initialization is to setup our URLMonitor to watch the LCDS server. Again, this is only for development.

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
						applicationComplete="init()">
	<mx:Script>
		<![CDATA[  
{...imports go here...} 
 		[Bindable]
		private var companies:ArrayCollection = new ArrayCollection();			
		private var companyDS:DataService;
			
		private var monitor:URLMonitor;
			
		private function init():void{
 			companyDS = new DataService("crm-company");
 			companyDS.cacheID = "insideRIATest";
 				
 			companyDS.addEventListener(MessageEvent.MESSAGE, handleDSMessage);
 			companyDS.addEventListener(DataServiceFaultEvent.FAULT, handleServiceFault);
 			
 			/*
 			Establish DS channel
 			*/
 			var channel:RTMPChannel = new RTMPChannel("my-rtmp", "rtmp://localhost:2037");
 			var channelSet:ChannelSet = new ChannelSet();
 			channelSet.addChannel(channel);
 			companyDS.channelSet = channelSet;
 				
 			/*
 			init network monitor
 			We're just going to monitor the LCDS server
 			*/
 			monitor = new URLMonitor(new URLRequest("http://localhost:8400"));
 			monitor.addEventListener(StatusEvent.STATUS, handleMonitorStatus);
 			monitor.start();
 		}  
{...rest of mx:Script code goes here...} 
		]]>
	</mx:Script> 
   {...ui goes here...} 
</mx:WindowedApplication>
Listing 2 - Application initialization (Note: Full source download link at end of article)

Putting it All Together

The application is initialized and we're ready to tie the UI to the data. The most meat of Listing 3 is the handleMonitorStatus event handler. This function sets autoSaveCache, autoCommit, and autoConnect. Stay with me here because you might think I'm telling a lie...but I'm not. To save your data to a local SQLite database, all you have to do is set autoSaveCache to true. Seriously, that is it. I didn't want to believe it either but our application data will automatically save the data locally without us manually making a database, messing with SQL syntax, etc. You can toggle this to control when you want data saved locally or you can also manually save data by using the saveCache function on the DataService as well as clear the cache using the clearCache function.

autoCommit tells the DataService to commit the pending changes to the server immediately, instead of queuing them for later. One thing to understand is this will try a commit instantly and will throw an error if the user is offline. You could watch for this error and call saveCache(...) instead of toggling autoSaveCache, if you wanted granular control over the cache. autoConnect is similar to autoCommit. When true the DataService will try to connect to the service and throw an error if a connection cannot be established. The only other thing we do in handleMonitorStatus is set the status bar to "Online" or "Offline (saving updates locally)" then call the getData function to load/refresh the data. Keep in mind handleMonitorStatus is toggling the DataService from online to offline, or vice versa, so calling getData will tell the companyDS to fill the companies ArrayCollection with data. Well, if we're offline, where does the DataService get the data? If we are online fill(..) will get the data from the server and from the local cache when offline. Since our DataGrid uses databinding for the dataProvider it will be updated automatically so we don’t have to worry about handling results from the fill() call. It means we do not have to write code for retrieving data online versus offline (ie - getRemoteData and getLocalData).

private function getData():void{
 	companyDS.fill(companies);
}

private function handleMonitorStatus(event:StatusEvent):void{
 	trace("monitor status: " + monitor.available);
 	companyDS.autoSaveCache = monitor.available;
 	companyDS.autoCommit = monitor.available;
 	companyDS.autoConnect = monitor.available;
 	
 	status = monitor.available ? "Online" : "Offline (saving updates locally)";
 	
 	getData();
}

private function showNewCompanyWindow():void{
 	var window:CompanyView = new CompanyView();
 	window.alwaysInFront = true;
 	window.open(true);
 	
 	enabled = false;
 	
 	window.addEventListener("save", handleSave);
 	window.addEventListener(Event.CLOSE, handleWindowClose);
}

private function handleSave(event:Event):void{
 	var window:CompanyView = CompanyView(event.target);
 	var newCompany:Company = window.company;
 	
 	if(!companies.contains(newCompany)){
  		companies.addItem(newCompany);
  	}else{
  		//update the company or alert the user of a duplicate
  	}
 	
 	window.close();
}
private function handleWindowClose(event:Event):void{
 	enabled = true;
}

private function handleDSMessage(event:MessageEvent):void{
 	//trace(event.message);
}

private function handleServiceFault(event:DataServiceFaultEvent):void{ 
 	trace("fault", event.message);
}

private function deleteCompany():void{
 	companies.removeItemAt(companiesGrid.selectedIndex);
} 
Listing 3 - Remaining mx:Script block (Note: Full source download link at end of article)

Take a look at Listing 1 again. You can see the "+" button has a click handler which calls showNewCompanyWindow(). This function creates a new application window based on the CompanyView component (see Listing 4). This is a simple MXML component taken from the full CRM sample app and tweaked to work in our application. The only purpose of this window is to allow a user to create a new company, click Save, and dispatch an event. There is a public variable named company which is used to store the data using databinding. In reverse the form is bound to the company variable so we could use this same form to allow for edits to a company. Edits are not integrated, at this point, but you could easily implement edit capabilities. This window also doesn’t validate the form. In a real application, the saveCompany() function would validate the form before dispatching the “save” event or validation would be done on the fly using a poka-yoke approach (http://rhjr.net/theblog/2007/04/21/poke-and-hope-and-poka-yoke/).

Let’s look at the flow for creating a new company. The “+” button is clicked and showNewCompanyWindow() is opened with an event listener added for the “save” and “close” events. For visual purposes we force the window to stay on the top and we disable the main application so it will fade out slightly, hopefully helping the user focus to the new window. Once the form is completed and the user clicks save, the handleSave function is called by way of the “save” event dispatched from the window. Once we have the user input, from the window.company variable, we do a check to see if the company exists in the companies ArrayCollection. If the company does not exist, simply add it to companies. The sweet part is when we’re online this information is sent to the server immediately, due to autoCommit being true. The sweeter part is when we’re offline, and/or when autoSaveCache is true, the information is automatically saved locally then when we get online again, and our URLMonitor triggers a handleMonitorStatus, the data is automatically sent to the server and all connected users are updated instantaneously.

<?xml version="1.0" encoding="utf-8"?>
<mx:Window xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:company="flex.samples.crm.company.*"
		   width="400" height="300" showGripper="true">
	<mx:Metadata>
		[Event(name="save")]
	</mx:Metadata>
	<mx:Script>
		<![CDATA[
			[Bindable]
        	private var industries:Array = ["Computers", "Health Care", "Manufacturing", "Textiles"];
        	
        	private function saveCompany():void{
         		dispatchEvent(new Event("save"));
         	}
		]]>
	</mx:Script>
	
	<mx:Binding source="companyName.text" destination="company.name"/>
	<mx:Binding source="address.text" destination="company.address"/>
	<mx:Binding source="city.text" destination="company.city"/>
	<mx:Binding source="state.text" destination="company.state"/>
	<mx:Binding source="zip.text" destination="company.zip"/>
	<mx:Binding source="companyIndustryCombo.selectedItem as String" destination="company.industry"/>
	
	<company:Company id="company" />

	<mx:Form width="100%" height="100%"  backgroundColor="#e6e6e6" id="companyForm">
	    <mx:FormItem label="Company Name" required="true">
	        <mx:TextInput id="companyName" width="250" text="{company.name}"/>
	    </mx:FormItem>
	    <mx:FormItem label="Address">
	        <mx:TextInput id="address" width="250" text="{company.address}"/>
	    </mx:FormItem>
	    <mx:FormItem label="City">
	        <mx:TextInput id="city" width="250" text="{company.city}"/>
	    </mx:FormItem>
	    <mx:FormItem label="State">
	        <mx:TextInput id="state" width="250" text="{company.state}"/>
	    </mx:FormItem>
	    <mx:FormItem label="Zip">
	        <mx:TextInput id="zip" width="250" text="{company.zip}"/>
	    </mx:FormItem>
	    <mx:FormItem label="Industry">
	        <mx:ComboBox id="companyIndustryCombo" dataProvider="{industries}" selectedItem="{company.industry}" width="250"/>
	    </mx:FormItem>
	</mx:Form>
	
	<mx:HBox>
		<mx:Button label="Save" click="saveCompany()" />
	</mx:HBox>
</mx:Window>
Listing 4 - CompanyView.mxml (Note: Full source download link at end of article)

The last UI functionality we incorporate is deleting an item. Listing 1 shows the “-“ button, when enabled, calls the deleteCompany function. In here we have another small piece of code that merely removes an item based on the selected index in the companiesGrid. The same applies here as it did with adding companies to companies. When online, it deletes the company online and from the cache. When offline, it deletes the company from the cache then pushes the delete request online when capable.

The Proof is in the CTRL+F11

How do we test? I’m glad you asked. Run the application from Flex Builder (CTRL+F11). Once it opens it will grab the latest data from the server, remember we have LCDS already open. Open the CRM Mini or full CRM, if you one isn’t already open. Feel free to test the application by deleting items or adding items. You will see the data updates instantly show up on the CRM you opened. Make edits in the CRM and you will see the application update as well. Sweet, huh? Yes, but that’s not all.

To see the magic, go to your Tomcat window and press CTRL+C. This will shutdown Tomcat and close the window. Go back to the application and manipulate the data (add or delete). You’ll see the grid update just as if you were online but the browser version of the CRM will not update because there is no server to communicate with and, if you created a company, the companyId will be 0. Start Tomcat. Sit back and just watch. Once the URLMonitor realizes the status of http://localhost:8400 is available and the “auto” properties are set to true, in handleMonitorStatus, all of your updates will be sent directly to the server and you will receive any new server updates. It is pretty amazing to watch your app take off and sync without you having to click a sync button or manually implement some sync logic, right? I know. Give the LCDS team a hug when you see them.

WorkingApp.jpg
Figure 6 - The working application.

It really feels like we should have to write more code or at least have more meetings about our synchronization approach, right? It is important to point out the small amount of code needed to add sync abilities to our app and the majority of the code is application code, meaning code pertaining to application functionality. In order to implement offline storage for this application we simply adjust three properties (autoSaveCache, autoCommit, and autoConnect) and call addItem or removeItemAt on our ArrayCollection to add or remove items. Within 11 lines of code, taking only what the DataService requires for connection and synchronization, the application is 100% offline enabled. Wow, this is powerful!

Next Steps

The very next thing to do is to get started. Take those 11 lines of code and update your application or start building a new one. Adobe has done the hard part. They took care of managing the cache and synchronization so all we, as developers, have to focus on is our application functionality.

A couple things we did not focus on within this article are conflict management and cache clearing. Seeing as we’re using LCDS, conflict management comes native. You can add a listener for a conflict event and manage them accordingly. The full CRM sample includes complete conflict management which you can use as a guide. As noted previously, a true offline experience would entail also listening for network events. Once you add the ability to edit companies, manage conflicts, and truly detect the user’s network state you can have a very powerful and capable application. One of the biggest things to know is this same offline capability is available within browser-based Flex application using shared objects. Sweet, huh? I know.

Thanks LCDS Team!

Resources

• Full Source Code for this article Download Source

• Adobe Labs: http://labs.adobe.com/technologies/livecycle_dataservices2_6/

• LCDS 2.6 Developer’s Guide: http://download.macromedia.com/pub/labs/livecycle_datservices/2.6/docs/lcds26_devguide_040908.pdf

• John C. Bland II (me), Geek loving LCDS: http://www.johncblandii.com

• Tom Jordhal, LCDS and BlazeDS team member: http://tjordahl.blogspot.com

• Christophe Coenraets, Senior Technical Evangelist : http://coenraets.org

• James Ward, RIA Cowboy: http://www.jamesward.org

About Author

John C. Bland II is founder of Katapult Media Inc. which focuses on software and web development using technologies such as ColdFusion, the Flash Platform, PHP, and the .NET Platform. Through Katapult, he works diligently on custom software and web products. As the manager of the Arizona Flash Platform User Group, John continues put back into the community which helped mold him into the developer he is today. John blogs regularly on his Geek Life blog: www.johncblandii.com.

Read more from John C Bland II. John C Bland II's Atom feed johncblandii on Twitter

Comments

49 Comments

John C. Bland II said:

FYI: LCDS 2.6 is public now. Be sure to check the latest docs for any changes in code.

http://www.adobe.com/products/livecycle/dataservices/

Also, another great resource on this topic is Christophe's InSync app: http://coenraets.org/blog/2008/05/insync-automatic-offline-data-synchronization-in-air-using-lcds-26/#more-80.

Manga Chizen said:

what the...

This is why people ignore the word LiveCycle when it comes to technology discussions..

Reading this end to end is like watching someone write 215 lines of code to output a button.

Adobe LDS = Epic Fail. Show me tools or move on..

John C. Bland II said:

Haha...wow Manga. I've never heard of LCDS (or LDS; j/k) referenced as an Epic Fail. :-)

Questions for ya:
What are your real gripes about LiveCycle?
What tools are you looking for specifically?

Let's open the discussion. Adobe is listening.

Lukas Ruebbelke said:

@Manga
what the...

Output a button? Are you kidding me? Did you even read the tutorial and work the code? I did and ended up with something just a TINY bit more useful than a button.

Show me a real gripe or move on..

Call me Labomba said:

Any chance of showing an LCDS installation on Java Application Server/Glassfish? I can't seem to find an article on this particular J2EE anywhere...

John C. Bland II said:

@Labomba
Have you tried installing it as a WAR then deploying it? I have no Glassfish experience so I couldn't tell you exactly but LCDS can install as a WAR.

Sky said:

Hi John,

Thanks for the example. I am trying to modify your example to work with a current app. that I'm working on. Before I spend too much time in this project, would you be able to tell me if what I want to do is possible?

The current project makes RPC to a ColdFusion backend which queries a database and returns the information. The goal is to make this application offline capable. So, if the user loses temporary Internet connectivity, the application will still run... and then when connectivity is restored, the data would automatically sync up.

It sounds like LCDS is a good solution for this problem, however, since the current app does not use LCDS would I have to change everything over to LCDS in order to make this workable? Or can I use RPC when there's Internet connection, and then switch to DataServices when the Internet is down?

Also, the remote DB is quite large ... with hundreds of tables. Will LCDS cache the whole DB locally? Would it cache the data retrieved? Or just the changed data?

Thanks.

John C. Bland II said:

You would need to use LCDS from jump. You can integrate LCDS directly into ColdFusion (http://www.coldfusiondeveloper.com.au/go/news/by/josh-rodgers/20080610-integrating-coldfusion-801-with-livecycle-ds-26-beta/) and flow from there.

So...to do what you want you can use the ease of the DataService or you can roll your own offline synchronization using sqlite directly.

Bottom line, it is 100% possible to build an app with offline synchronization without using LCDS or the DataService. Thing is...that article won't be 2500 words as you'll have much more code. :-)

Jin Lei said:

This demonstrates the integration of AIR with LCDS; Somehow, it also exposes that the challenging part of LCDS, synchronizing the data and conflicts control.

I ran the demo, and found problems -

synchronizing is not stable:
1. random empty row in the dbgrid;
2. duplicated the new added row(s);
3. removal action sometime can not take effects.

I checked the source code of client end, and believed, problem exists in the server end, or even the deep level - some LCDS packages.

Correct me if I'm wrong.

John C. Bland II said:

From your stable block there, I didn't have any of those results even when the app was terribly buggy in the beginning stages.

Are you sure you have LCDS installed properly?

Jin Lei said:


Thanks for your reply.

Another question when I moved forward to create a db and server end java code, after using ant to build java classes, tomcat just cannot restart properly.

I compared the generated .class files with the original one from LCDS, and found the sizes are different.

Any java compilation hints on server end codes?

Thanks

John C. Bland II said:

You might try to post some code, etc to the LiveCycle forums: http://www.adobeforums.com/webx/.3bc4344d/.

Your issue really depends on the errors you are receiving. The first thing I'd check is the Java version you used to compile.

Jin Lei said:

Thanks John,

I've made the end point working now.

Actually, I'm building an application Air (Flex + extjs) and offline synchronization with LCDS. For sure I need the flex-ajax-bridge.

But the experiments failed on Air runtime container, when ajax tried to communicate with server end data services.

And I found the topic on external interface when I attempted to make a Air Flex application with enclosed HTML(ajax) to communicate with data services.

http://livedocs.adobe.com/labs/air/1/aslr/flash/external/ExternalInterface.html

where it says -

Note: Adobe AIR currently does not support the ExternalInterface class.


Does it mean there is no way to build an Air+Ajax+LCDS application, currently?

Highly appreciated for any answer.

Jin Lei said:

Hi John,

I checked the flex-ajax-bridge and found something there, see

http://www.adobeforums.com/webx/.59b70d54

for details, Thanks.

John C. Bland II said:

I actually have no experience with air+js so I couldn't tell you man. Are you @ MAX? If so, email me directly and we can hook up. I'll introduce you to the LCDS guys who could absolutely help you.

Frank said:

Hi John,

I found your example on the web and I love it. So much, I want to demo it tomorrow.

I run it my macbook (osx), lifecycle 2.6 and AIR 1.5.

I always get the error when I start tomcat again, even when I didn't make any changes to the data.
The strange thing is that there seems to be a hardcode path in the corfu framework to the "C:" drive... A bit strange when running on OSX....

Could you help me out, to make the demo a succes?

Thanks in advance,

Frank

[RPC Fault faultString="Commit operation not allowed if a connection can't be established." faultCode="Client.Commit.Failed" faultDetail="Remote destination is not available."]
at mx.data::DataStore/dispatchCacheFaultEvent()[C:\depot\flex\branches\enterprise_corfu_b2\frameworks\projects\data\src\mx\data\DataStore.as:3156]
at Function/http://adobe.com/AS3/2006/builtin::apply()
at mx.rpc::AsyncDispatcher/timerEventHandler()[C:\autobuild\3.2.0\frameworks\projects\rpc\src\mx\rpc\AsyncDispatcher.as:50]
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()

John C. Bland II said:

(handled via email)

Kevin Merritt said:

I am having the same problem as Frank above. Any thoughts on a fix?
Thanks, Kevin

[RPC Fault faultString="Commit operation not allowed if a connection can't be established." faultCode="Client.Commit.Failed" faultDetail="Remote destination is not available."]

John C. Bland II said:

Kevin contacted me via email.

It seems setting autoConnect=true, indefinitely, fixes the issue.

Also note Frank, from above, found there to be issues with AIR 1.5. Upgrade your swc's to the latest build of lcds to resolve the issue.

bonny said:

Hi John,

I had download your code. But i am getting incomplete code. Can you please look at in this matter?


Thanks,
Bonny

bonny said:

Hi John,

http://www.johncblandii.com/downloads/LiveCycleAIROffline.zip.
this link is also not working it give error page cannot found.


thanks,
Nirvish

John C. Bland II said:

Odd, the link works for me.

Oh, the period is part of the url. Use this as the url: http://www.johncblandii.com/downloads/LiveCycleAIROffline.zip

Bonny said:

Hi John,

I am getting below error when i am trying to call my own dataservice. Could you please help me in this reagrds?


Error: Unable to initialize destinations on server: ["StreamTest"]
at ()[C:\depot\flex\branches\enterprise_corfu_b2\frameworks\projects\data\src\mx\data\DataStore.as:2305]
at ()[C:\depot\flex\branches\enterprise_corfu_b2\frameworks\projects\data\src\mx\data\DataStore.as:2321]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.data::SQLDBCache/dispatchStatusEvent()[C:\depot\flex\branches\enterprise_corfu_b2\frameworks\projects\airfds\src\mx\data\SQLDBCache.as:540]
at Function/http://adobe.com/AS3/2006/builtin::apply()
at mx.rpc::AsyncDispatcher/timerEventHandler()[E:\dev\3.0.x\frameworks\projects\rpc\src\mx\rpc\AsyncDispatcher.as:50]
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()


Thanks,
Bonny

Bonny said:

Hi John,

I am getting below error on server when i am trying to call my own dataservice. Could you please help me in this reagrds?

10:38:50,002 INFO [STDOUT] [Flex] [ERROR] Exception when invoking service: (non
e)
with message: Flex Message (flex.data.messages.DataMessage)
operation = fill
id = null
clientId = 2C0AA277-17E7-FA52-3402-E0182A22F34C
correlationId =
destination = PagingDestination
messageId = 1222FB28-CE75-6EB6-5FE5-E0183703DECA
timestamp = 1232120330002
timeToLive = 0
body =
[

]
hdr(DSEndpoint) = my-rtmp
hdr(DSId) = 611B1E72-F21A-DE83-F613-3827868EEE92
hdr(pageSize) = 500
exception: flex.messaging.MessageException: No destination with id 'StreamTest' is registered with any service.

Souvik Mukherjee said:

I am developing an application and I am in a position where I can push messages to one or many AIR applications and the selection of AIR application will be decided by LCDS server. Here I am making use of JMS along with JMS adapter. I need a way to receive an acknowledgement to LCDS server when the message is delivered.
I have found few application where JMS subscriber is sending acknowledgement to JMS producer, but I need a way where JMS producer is getting acknowledgement from each Flex client.

John C. Bland II said:

Bonny
I helped you via email, right?

Souvik
Are you saying you want to know on the server when the flex client receives the message (ie - delivery confirmation) or you want to know in the client when a message comes in? I'm not quite sure which way you mean.

Souvik Mukherjee said:

I want to know on the server when the flex client receives the message (ie - delivery confirmation) . Please suggest.

John C. Bland II said:

I haven't fooled with that need/requirement. You may be able to utilize something in JMS to listen for delivery.

Yakov Fain said:

We are about to publish a generic data sync solution for AIR/BlazeDS using one of the components of from our Clear Toolkit library. I've recorded a demo shoing it in action: http://flexblog.faratasystems.com/?p=394

John C. Bland II said:

Congrats.

Deepa said:

Hi

i have a specific requirement.
i would like to cache a web pahe when i go offline without using any data base but using LCDS .
Is it possible.

Thanks in advance

John C. Bland II said:

I'm not 100% sure why you'd use LCDS. If you're caching it, I assume you mean you want to see the entire site offline which would mean you'd have to crawl/download each file. Am I missing something or is that what you're looking to do?

Arun said:

Hi,

i have two problems:

1. when i set monitor.pollInterval =4000; and i run the application DataGrid doesnt get populated at all. if i comment the above line it gets populated

2. My CRM is not at all getting populated though i keep the server on

Deepa said:

Hi John,

My requirement is something like this.

i want to post some xml request and get a response in turn from my server even though i go to offline mode.

Let me explain this now.

when i am online i post a xml file ussing an HTTP request to my server( i am not using any Data Base here) and get a response .
When i am offline i dont want user to let know he is offline.. i still want to send the xml file and get the result say may be cached Result.When he goes to online again automatic sync should happen and the result should be cached.

Is it possible to have this kind of requirement without using DataService? because DataService needs a DataBase at the server as well.

Is it possible to have this without using DataService but using any other feature like RemoteService etc?

Thanks
Deepa

John C. Bland II said:

@Deepa
So, this sounds like you would want to roll your own system here since you're not using a DB. You wouldn't be able to get a response from the server when they went offline. About all you could do is store their request while offline then publish it after they come online again. Essentially, a custom offline solution.

@Arun
Did you grab the updated code: http://www.johncblandii.com/downloads/LiveCycleAIROffline.zip?

Arun said:

HI John,

Now the poll is working fine but still CRM is not getting updated.
i opened the mini CRM available in example.

Thanks
Arun

Arun said:

John,

i would like to understand one scenario..

i am running livecycle offline application(http://www.johncblandii.com/downloads/LiveCycleAIROffline.zip?) and say my server is down
i update some records, these records will be saved in local cache
next i switch on the server but keep my application running as it is..which means to say i will not press refresh button , in this case since my server is up and i am online will local DB get synced with server DB? (without me doing anything.. that is without pressing refresh button?)
Whether LCDS does this detection , like a service running in back ground?


Linda said:

i am trying to connect HSQL DB using sql assemebler.

i get an error saying no paremeters passed to fill method for the sql assembler on destination

my sql assembler statement looks like this


flex.data.assemblers.SQLAssembler
application









org.hsqldb.jdbcDriver
jdbc:hsqldb:hsql://localhost:8009/flexdemodb
sa

15



Company


all
SELECT * FROM TASKLITE ORDER BY NAME ASC


by-name
SELECT * FROM TASKLITE WHERE NAME LIKE CONCAT('%', CONCAT(#searchStr#,'%'))



SELECT * FROM TASKLITE WHERE PRODUCT_ID = #TASKLITEID#



INSERT INTO TASKLITE
(NAME, ADDRESS, CITY, ZIP, STATE, INDUSTRY )
VALUES (#NAME#, #ADDRESS#, #CITY#, #ZIP#, #STATE#, #INDUSTRY #)
CALL IDENTITY()




John C. Bland II said:

@arun / @linda

I did not see these comments come through to my email. I sincerely apologize for not getting back to you. Do you still need assistance?

Ryan said:

Thanks for the example. I am trying to modify your example to work with a current app. that I'm working on for a dating tips blog.

John C. Bland II said:

Let us know how it goes Ryan.

Tanakorn said:

I use LCDS 2.6.1 with Air 1.5

When I press the "-" button the app. will show

"undefined
at mx.data::CommitResponder/result()[C:\depot\DataServices\branches\lcds26_hotfixes\frameworks\projects\data\src\mx\data\CommitResponder.as:432]
at mx.rpc::AsyncRequest/acknowledge()[C:\autobuild\3.2.0\frameworks\projects\rpc\src\mx\rpc\AsyncRequest.as:74]
at NetConnectionMessageResponder/resultHandler()[C:\autobuild\3.2.0\frameworks\projects\rpc\src\mx\messaging\channels\NetConnectionChannel.as:515]
at mx.messaging::MessageResponder/result()[C:\autobuild\3.2.0\frameworks\projects\rpc\src\mx\messaging\MessageResponder.as:199]"

I don't know what happen.

John C. Bland II said:

@Tanakom
I'm not quite sure there. Does your app create and read records just fine?

Tanakorn said:

1. The read process (in the first time) is work right.

2. When I add the new company the companyId = 0 and it show:

undefined
at mx.data::CommitResponder/result()[C:\depot\DataServices\branches\lcds26_hotfixes\frameworks\projects\data\src\mx\data\CommitResponder.as:432]
at mx.rpc::AsyncRequest/acknowledge()[C:\autobuild\3.2.0\frameworks\projects\rpc\src\mx\rpc\AsyncRequest.as:74]
at NetConnectionMessageResponder/resultHandler()[C:\autobuild\3.2.0\frameworks\projects\rpc\src\mx\messaging\channels\NetConnectionChannel.as:515]
at mx.messaging::MessageResponder/result()[C:\autobuild\3.2.0\frameworks\projects\rpc\src\mx\messaging\MessageResponder.as:199]

3. when I Delete the company it show the above error.

So, I was try this demo app. in development environment, which mean I not yet deploy the app. but use "run" button in flex builder to run the app.

May you advise me that what factor I should check for issue?

Thank you very much.
Tanakorn Numrubporn

John C. Bland II said:

@Tanakorn
Did you try the latest source: http://www.johncblandii.com/downloads/LiveCycleAIROffline.zip?

Tanakorn said:

OH! Thank for your very quickly and kindly reply. The issue is, when I run your app. I run in flex builder and not yet install .air file. So, when I export to .air file and install it, your demo app. work well (even in old version).

Other issue (with new version):
1. If I delete some company in offline status, when server come back to online status the datagrid will refresh to show that the row that I just delete was empty row and it disable status (mean can't click on it).

Thank you for this tutorial and your goodwill.

Tanakorn Numrubporn

John C. Bland II said:

@Tanakorn
That's interesting. You should be able to test within Flex Builder.

Try changing your cacheid then try to delete again. At times it can have problems with stale data not saving properly.

Emo said:

I did not see these comments come through to my email. I sincerely apologize for not getting back to you. Do you still need assistance?
emo

Leave a comment


Tag Cloud

iPad

What's your take on the iPad? (Putting aside the Flash/iPad flame war)

Answer

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.