- 浏览: 4370 次
- 性别:
- 来自: 深圳
最新评论
原文 :
http://coenraets.org/blog/2008/05/insync-automatic-offline-data-synchronization-in-air-using-lcds-26/
Flex :
首先要下载转为LCDS提供服务的fds.swc
AIR App
ContactForm.mxml
Contact.as
data-management-config.xml
JAVA 需要有LCDS
http://coenraets.org/blog/2008/05/insync-automatic-offline-data-synchronization-in-air-using-lcds-26/
Flex :
首先要下载转为LCDS提供服务的fds.swc
AIR App
<?xml version="1.0" encoding="utf-8"?> <!-- Christophe Coenraets, christophe@coenraets.org - http://coenraets.org --> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" layout="absolute" showFlexChrome="false" showStatusBar="false" width="400" height="600" currentState="small" applicationComplete="init()"> <mx:states> <mx:State name="big"> <mx:SetProperty name="width" value="850"/> <mx:SetProperty target="{tn}" name="visible" value="true"/> </mx:State> <mx:State name="small"> <mx:SetProperty name="width" value="400"/> <mx:SetProperty target="{tn}" name="visible" value="false"/> </mx:State> </mx:states> <mx:Script> <![CDATA[ import mx.data.events.DataServiceFaultEvent; import mx.data.DataService; import mx.rpc.AsyncResponder; import air.net.SocketMonitor; import mx.messaging.channels.RTMPChannel; import mx.messaging.Channel; import mx.messaging.ChannelSet; import mx.data.Conflicts; import mx.rpc.AsyncToken; import mx.data.events.DataConflictEvent; import mx.data.Conflict; import mx.controls.Alert; [Embed(source='/assets/sync_light.swf', symbol='icon_online')] private var iconOnline:Class; [Embed(source='/assets/sync_light.swf', symbol='icon_offline')] private var iconOffline:Class; private var host:String = "localhost"; private var port:int = 2037; private var socketMonitor:SocketMonitor; [Bindable] private var ds:DataService; private function init():void { ds = new DataService("insync"); ds.cacheID = "insync19"; ds.autoSaveCache = false; ds.autoConnect = false; ds.autoCommit = false; ds.addEventListener(DataConflictEvent.CONFLICT, conflictHandler); ds.addEventListener(DataServiceFaultEvent.FAULT, faultHandler); var cs:ChannelSet = new ChannelSet(); var rtmpChannel:Channel = new RTMPChannel("my-rtmp", "rtmp://" + host + ":" + port); cs.addChannel(rtmpChannel); ds.channelSet = cs; socketMonitor = new SocketMonitor(host, port); socketMonitor.pollInterval = 3000; socketMonitor.addEventListener(StatusEvent.STATUS, networkStatusChangeHandler); socketMonitor.start(); } private function networkStatusChangeHandler(event:StatusEvent):void { trace("networkStatusChangeHandler() socketMonitor.available: " + socketMonitor.available); if (socketMonitor.available) { // The network just became available. // The dataService should not be connected at this time. But in case it is, we do not try to reconnect. // If (as expected) the dataService is not connected, we connect before handling offline changes if (ds.connected) { trace("DataService is already connected"); handleOfflineChanges(); } else { connect(); } } else { if (contacts.length == 0) { // contacts haven't beeen retrieved yet: we are starting the application offline. // contacts will be filled from cache. fill(); } } } private function connect():void { trace("Connecting..."); var token:AsyncToken = ds.connect(); token.addResponder(new AsyncResponder( function(result:Object, token:Object = null):void { trace("ds.connect(): success"); // We are online: check if there are offline changes to apply. handleOfflineChanges(); }, function(error:Object, token:Object = null):void { trace("ds.connect(): failure"); // We are offline: fill data from cache. fill(); })); } private function handleOfflineChanges():void { if (ds.connected && ds.commitRequired) { trace("Committing offline changes..."); var token:AsyncToken = ds.commit(); token.addResponder(new AsyncResponder( function(result:Object, token:Object = null):void { trace("ds.commit(): success"); Alert.show("Changes have been made offline and have been synchronized with the server", "Data Synchronization"); displayOfflineStatus(); fill(); }, function(error:Object, token:Object = null):void { trace("ds.commit(): failure"); Alert.show("Cannot commit offline changes", "Data Synchronization Error"); })); } else { trace("No offline changes to apply"); fill(); } } private function fill():void { // Load the contacts. If we are offline contacts will be loaded from the cache (if it exists) trace("Filling..."); var asyncToken:AsyncToken = ds.fill(contacts); asyncToken.addResponder(new AsyncResponder( function(result:Object, token:Object = null):void { trace("ds.fill(): success"); trace("ds.saveToCache()"); ds.saveCache(); }, function(error:Object, token:Object = null):void { trace("ds.fill(): failure"); Alert.show("Cannot fill"); })); } public function openTab(contact:Object):void { currentState = "big"; var children:Array = tn.getChildren(); var length:int = children.length; for (var i:int = 0; i<length; i++) { if (children[i].contact == contact) { tn.selectedIndex = i; return; } } var form:ContactForm = new ContactForm(); tn.addChild(form); form.ds = ds; form.contacts = contacts; form.contact = contact as Contact; tn.selectedChild = form; } public function displayOfflineStatus():void { var children:Array = tn.getChildren(); var length:int = children.length; for (var i:int = 0; i<length; i++) { ContactForm(children[i]).displayOfflineStatus(); } } private function createItem():void { openTab(new Contact()) } private function faultHandler(event:DataServiceFaultEvent):void { // fail silently for now. We catch errors on a per method basis. trace(event.fault.faultString); } private function conflictHandler(event:DataConflictEvent):void { // TODO: provide fine grained conflict resolution options to the user. var conflicts:Conflicts = ds.conflicts; for (var i:int=0; i<conflicts.length; i++) { var conflict:Conflict = conflicts.getItemAt(i) as Conflict; if (!conflict.resolved) { conflict.acceptServer(); } } Alert.show("There were " + conflicts.length + " conflicts. Contacts have been reloaded from the server.", "Conflict"); } private function toggleMaximize():void { currentState = currentState=="small" ? "big" : "small"; } private function childRemoveHandler():void { if (tn.numChildren == 1) { currentState = "small"; } } ]]> </mx:Script> <mx:Style source="styles.css"/> <mx:ArrayCollection id="contacts"/> <mx:Canvas id="container" styleName="appContainer" left="12" right="12" top="12" bottom="12"> <mx:Canvas left="20" top="14" right="20" mouseDown="nativeWindow.startMove()"> <mx:Canvas backgroundColor="#006699" width="36" height="36" verticalCenter="0"/> <mx:Label text="in" fontSize="24" color="#FFFFFF" x="7" verticalCenter="0"/> <mx:Label text="Sync" styleName="appTitle" x="38" verticalCenter="0"/> <mx:Button icon="@Embed('assets/icon_plus.png')" width="32" height="32" click="createItem()" x="120" verticalCenter="0"/> <mx:Button styleName="iconMinimize" verticalCenter="0" right="26" click="minimize()"/> <mx:Button styleName="iconMaximize" verticalCenter="0" right="13" click="toggleMaximize()"/> <mx:Button styleName="iconClose" verticalCenter="0" right="0" click="close()"/> </mx:Canvas> <mx:HBox top="60" bottom="50" left="18" right="18"> <mx:DataGrid id="list" width="340" height="100%" dataProvider="{contacts}" doubleClick="openTab(list.selectedItem)" doubleClickEnabled="true"> <mx:columns> <mx:DataGridColumn dataField="firstName" headerText="First Name"/> <mx:DataGridColumn dataField="lastName" headerText="Last Name"/> <mx:DataGridColumn dataField="phone" headerText="Phone"/> </mx:columns> </mx:DataGrid> <mx:TabNavigator id="tn" width="100%" height="100%" childRemove="childRemoveHandler()"/> </mx:HBox> <mx:HRule left="8" right="8" bottom="40"/> <mx:Canvas left="20" bottom="17" right="20"> <mx:Image source="{ds.connected?iconOnline:iconOffline}" toolTip="{ds.connected?'Online':'Offline'}" verticalCenter="-1"/> <mx:Label text="{ds.connected?'Online':'Offline'}" left="13" verticalCenter="0"/> <mx:Label text="Commit required: {ds.commitRequired}" left="60" verticalCenter="0"/> </mx:Canvas> </mx:Canvas> </mx:WindowedApplication>
ContactForm.mxml
<?xml version="1.0" encoding="utf-8"?> <!-- Christophe Coenraets, christophe@coenraets.org - http://coenraets.org --> <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" width="100%" height="100%"> <mx:Script> <![CDATA[ import mx.controls.Alert; import mx.collections.ArrayCollection; import mx.data.messages.DataMessage; import mx.rpc.AsyncResponder; import mx.rpc.AsyncToken; import mx.data.DataService; private var _contact:Contact; public function set contact(contact:Contact):void { if (contact != _contact) { _contact = contact; if (contacts.contains(contact)) { label = contact.firstName + " " + contact.lastName; } else { label = "New Contact"; } displayOfflineStatus(); dispatchEvent(new Event("contactChanged")); } } [Bindable(event="contactChanged")] public function get contact():Contact { return _contact; } [Bindable] public var contacts:ArrayCollection; [Bindable] public var ds:DataService; private function save():void { contact.firstName = firstName.text; contact.lastName = lastName.text; contact.title = contactTitle.text; contact.email = email.text; contact.phone = phone.text; if (!contacts.contains(contact)) { trace("Adding contact"); contacts.addItem(contact); } label = contact.firstName + " " + contact.lastName; commit(); } private function deleteItem():void { ds.deleteItem(contact); commit(); parent.removeChild(this); } private function commit():void { if (ds.connected) { if (ds.commitRequired) { trace("Online: Committing contact..."); var token:AsyncToken = ds.commit(); token.addResponder(new AsyncResponder( function(result:Object, token:Object = null):void { trace("ds.commit(): success"); trace("ds.saveCache()"); ds.saveCache(); }, function(error:Object, token:Object = null):void { trace("ds.commit(): failure"); Alert.show("Error committing changes"); })); } } else { trace("Offline: Saving to cache..."); var t:AsyncToken = ds.saveCache(); t.addResponder(new AsyncResponder( function(result:Object, token:Object = null):void { trace("ds.saveCache(): success"); displayOfflineStatus(); }, function(error:Object, token:Object = null):void { trace("ds.saveCache(): failure"); })); } } public function displayOfflineStatus():void { var newStatus:String; switch (ds.getPendingOperation(contact)) { case DataMessage.CREATE_OPERATION: newStatus = "CREATE"; break; case DataMessage.UPDATE_OPERATION: newStatus = "UPDATE"; break; case DataMessage.DELETE_OPERATION: newStatus = "DELETE"; break; case DataMessage.UNKNOWN_OPERATION: newStatus = "NOT MOFIFIED"; break; } status.text = "Offline status: " + newStatus; } ]]> </mx:Script> <mx:Form width="100%" height="100%"> <mx:FormItem label="Id"> <mx:TextInput id="contactId" text="{contact.contactId}" enabled="false"/> </mx:FormItem> <mx:FormItem label="First Name"> <mx:TextInput id="firstName" text="{contact.firstName}"/> </mx:FormItem> <mx:FormItem label="Last Name"> <mx:TextInput id="lastName" text="{contact.lastName}"/> </mx:FormItem> <mx:FormItem label="Title"> <mx:TextInput id="contactTitle" text="{contact.title}"/> </mx:FormItem> <mx:FormItem label="Phone"> <mx:TextInput id="phone" text="{contact.phone}"/> </mx:FormItem> <mx:FormItem label="Email"> <mx:TextInput id="email" text="{contact.email}"/> </mx:FormItem> </mx:Form> <mx:Label id="status" right="8" left="8" bottom="38" visible="{!ds.connected}" color="#BBBBBB"/> <mx:Button label="Close Tab" click="parent.removeChild(this)" left="10" bottom="8" width="80"/> <mx:Button label="Save" click="save()" right="10" bottom="8" width="80"/> <mx:Button label="Delete" click="deleteItem()" right="94" bottom="8" width="80"/> </mx:Canvas>
Contact.as
// Christophe Coenraets, christophe@coenraets.org - http://coenraets.org package { [Managed] [RemoteClass(alias="lcds.samples.contact.Contact")] public class Contact { public var contactId:int; public var firstName:String; public var lastName:String; public var title:String; public var phone:String; public var email:String; } }
data-management-config.xml
<destination id="custom-contact"> <adapter ref="java-dao"/> <properties> <source>lcds.samples.contact.ContactAssembler</source> <scope>application</scope> <metadata> <identity property="contactId" undefined-value="0"/> </metadata> <network> <paging enabled="false" pageSize="10" /> </network> </properties> </destination>
JAVA 需要有LCDS
package lcds.samples.contact; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; public class BaseDAO { // Convenience method protected List getList(String sql) throws DAOException { return getList(sql, new Object[] {}); } // Convenience method protected List getList(String sql, int startRow, int pageSize) throws DAOException { return getList(sql, new Object[] {}, startRow, pageSize); } // Convenience method protected List getList(String sql, Object param) throws DAOException { return getList(sql, new Object[] {param}); } protected List getList(String sql, Object[] params) throws DAOException { return getList(sql, params, 1, 0); } protected List getList(String sql, Object[] params, int startRow, int pageSize) throws DAOException { List list = new ArrayList(); Connection c = null; ResultSet rs = null; PreparedStatement ps = null; try { c = ConnectionHelper.getConnection(); ps = c.prepareStatement(sql); if (params != null) { for (int i=0; i<params.length; i++) { ps.setObject(i+1, params[i]); } } rs = ps.executeQuery(); for (int i=1; i<startRow; i++) { rs.next(); } int count = 0; while (rs.next() && (pageSize==0 || count<pageSize)) { Object obj = rowToObject(rs); list.add(obj); count++; } } catch (SQLException e) { e.printStackTrace(); throw new DAOException(e); } finally { ConnectionHelper.close(c); } return list; } /* protected Object getItem(String sql, int pk) throws DAOException { Integer[] params = {new Integer(pk)}; List list = getList(sql, params); if (list != null && list.size()>0) { return list.get(0); } else { return null; } } */ protected Object getItem(String sql, Object pk) throws DAOException { Object[] params = { pk }; List list = getList(sql, params); if (list != null && list.size()>0) { return list.get(0); } else { return null; } } protected Object rowToObject(ResultSet rs) throws SQLException { throw new SQLException("Row processor not implemented"); } protected int createItem(String sql, Object[] params) throws DAOException { Connection c = null; try { c = ConnectionHelper.getConnection(); executeUpdate(sql, params, c); Statement s = c.createStatement(); //ResultSet rs = s.executeQuery("SELECT LAST_INSERT_ID()"); ResultSet rs = s.executeQuery("CALL IDENTITY()"); rs.next(); int pk = rs.getInt(1); return pk; } catch (SQLException e) { e.printStackTrace(); throw new DAOException(e); } finally { ConnectionHelper.close(c); } } public int executeUpdate(String sql, Object[] params) throws DAOException { Connection c = null; try { c = ConnectionHelper.getConnection(); return executeUpdate(sql, params, c); } catch (SQLException e) { e.printStackTrace(); throw new DAOException(e); } finally { ConnectionHelper.close(c); } } public int executeUpdate(String sql, Object[] params, Connection connection) throws DAOException { int rows = -1; PreparedStatement ps = null; try { ps = connection.prepareStatement(sql); if (params != null) { for (int i=0; i<params.length; i++) { ps.setObject(i+1, params[i]); } } rows = ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); throw new DAOException(e); } return rows; } }
package lcds.samples.contact; public class ConcurrencyException extends Exception { private static final long serialVersionUID = -6405818907028247079L; public ConcurrencyException(String message) { super(message); } public ConcurrencyException(Throwable cause) { super(cause); } public ConcurrencyException(String message, Throwable cause) { super(message, cause); } }
package lcds.samples.contact; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ConnectionHelper { private String url; private static ConnectionHelper instance; private ConnectionHelper() { try { Class.forName("org.hsqldb.jdbcDriver"); url = "jdbc:hsqldb:hsql://localhost:9002/contactdb"; } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { if (instance == null) { instance = new ConnectionHelper(); } try { return DriverManager.getConnection(instance.url); } catch (SQLException e) { throw e; } } public static void close(Connection connection) { try { if (connection != null) { connection.close(); } } catch (SQLException e) { e.printStackTrace(); } } }
package lcds.samples.contact; public class Contact { private int contactId; private String firstName; private String lastName; private String title; private String phone; private String email; public int getContactId() { return contactId; } public void setContactId(int contactId) { this.contactId = contactId; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
package lcds.samples.contact; import java.util.List; import java.util.Map; import java.util.Collection; import flex.data.DataSyncException; import flex.data.assemblers.AbstractAssembler; public class ContactAssembler extends AbstractAssembler { private ContactDAO dao = new ContactDAO(); public Collection fill(List fillParameters) { if (fillParameters.size() == 0) { return dao.findAll(); } String queryName = (String) fillParameters.get(0); if (queryName.equals("by-name")) { return dao.findByName((String) fillParameters.get(1)); } return super.fill(fillParameters); // throws a nice error } public Object getItem(Map uid) { return dao.getContact(((Integer) uid.get("contactId")).intValue()); } public void createItem(Object newVersion) { dao.create((Contact) newVersion); } public void updateItem(Object newVersion, Object prevVersion, List changes) { int contactId = ((Contact) newVersion).getContactId(); try { dao.update((Contact) newVersion); } catch (ConcurrencyException e) { System.err.println("*** Throwing DataSyncException when trying to update contact id=" + contactId); throw new DataSyncException(dao.getContact(contactId), changes); } } public void deleteItem(Object prevVersion) { try { dao.delete((Contact) prevVersion); } catch (ConcurrencyException e) { int contactId = ((Contact) prevVersion).getContactId(); System.err.println("*** Throwing DataSyncException when trying to delete company id=" + contactId); throw new DataSyncException(dao.getContact(contactId), null); } } }
package lcds.samples.contact; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; public class ContactDAO extends BaseDAO { public List findAll() { return getList("SELECT * FROM contact ORDER BY last_name, first_name"); } public List findByName(String name) { return getList("SELECT * FROM contact WHERE UPPER(first_name) LIKE ? OR UPPER(last_name) LIKE ? ORDER BY last_name, first_name", new Object[] {"%"+name.toUpperCase()+"%", "%"+name.toUpperCase()+"%"}); } public Object getContact(int contactId) { return getItem("SELECT * FROM contact WHERE contact_id=?", contactId); } public void create(Contact contact) throws DAOException { log("Creating contact: " + contact.getFirstName() + " " + contact.getLastName()); int contactId = createItem("INSERT INTO contact (first_name, last_name, title, phone, email) VALUES (?,?,?,?,?)", new Object[] { contact.getFirstName(), contact.getLastName(), contact.getTitle(), contact.getPhone(), contact.getEmail() }); contact.setContactId(contactId); log("Contact created successfully - contactId: " + contact.getContactId()); } public void update(Contact contact) throws DAOException, ConcurrencyException { log("Updating contact: " + contact.getContactId() + " " + contact.getFirstName() + " " + contact.getLastName()); int rows = executeUpdate("UPDATE contact SET first_name=?, last_name=?, title=?, phone=?, email=? WHERE contact_id=?", new Object[] { contact.getFirstName(), contact.getLastName(), contact.getTitle(), contact.getPhone(), contact.getEmail(), contact.getContactId() }); if (rows == 0) { throw new ConcurrencyException("Item not found"); } log("Contact updated successfully"); } public void delete(Contact contact) throws DAOException, ConcurrencyException { log("Deleting contact: " + contact.getContactId() + " " + contact.getFirstName() + " " + contact.getLastName()); int rows = executeUpdate("DELETE FROM contact WHERE contact_id = ?", new Object[] {new Integer(contact.getContactId())}); if (rows == 0) { throw new ConcurrencyException("Item not found"); } log("Contact deleted successfully"); } protected Object rowToObject(ResultSet rs) throws SQLException { Contact contact = new Contact(); contact.setContactId(rs.getInt("contact_id")); contact.setFirstName(rs.getString("first_name")); contact.setLastName(rs.getString("last_name")); contact.setTitle(rs.getString("title")); contact.setPhone(rs.getString("phone")); contact.setEmail(rs.getString("email")); return contact; } private void log(String message) { System.out.println("# " + message); } }
package lcds.samples.contact; public class DAOException extends RuntimeException { private static final long serialVersionUID = -8852593974738250673L; public DAOException(String message) { super(message); } public DAOException(Throwable cause) { super(cause); } public DAOException(String message, Throwable cause) { super(message, cause); } }
- insync.zip (1.1 MB)
- 下载次数: 1
相关推荐
Flex LCDS flex.war就是lcds.war Flex+LCDS使用的war包
flex+lcds实例,适合初学者学习FLEX和LCDS,描述了FLEX与LCDS构建的基本框架。
Flex LCDS Java 简单教程 源码
构建第一个Flex LCDS的例子供大家参考
Flex LCDS的例子 felx基础整合java 与调用java的基础方法。。。新手必看
1、flex lcds; 2、用户登录; 3、代码; 4、mysql;
flex lcds3.1 亲测可用 LiveCycle Data Service
live cycle data service 是flex整合J2EE作ria开发包
Flex LCDS JAVA 入门学习教程
LiveCycle ES Developer's Guide--lcds26_devguide_040908
入门教程,图文并茂 主要介绍如何建立FlexLCDS工程,及相关配置。 主要如何用remoteObject来连接实现Flex与Java的通信 自己是初学者,看着觉得挺容易上手的,就推荐下了。
此资源有误,请勿下载,暂未找到删除资源办法
Flex + LCDS +JAVA入门教程,描述了flex通过LCDS与java进行
学习flex lcds java的好东东,
很多人在帖子和群中问到过一些关于建立Flex+LCDS(FDS)工程的问题,由于操作上的东西,很难简单说清楚,于是写了一个简单的教程(本来很早就答应过的,结果被newfish逮住做东西,加上公司的事,一直抽不出时间哈,...
Flex + LCDS + Java Flex + LCDS + Java