Wednesday, July 22, 2009

Adobe Dev Summit, 2009

Adobe Dev Summit, 2009 has been announced. The summit is on 4th August, 2009 at Lalit Ashok, Bangalore. You can sign up for a Gold pass, which is absolutely free. You can also sign up for a Platinum pass and get Flex Builder 3 Professional license for free.

What’s in it for you?

  • See the new, improved and rocking LiveCycle Data Services 3 in action! If you are a Java developer, you wouldn’t want to miss this one!
  • If you are a PHP/Java developer, get on the RIA expressway using the new Data Centric Development features on Adobe Flash Builder 4
  • If you’re into enterprise-wide RIA development, things have just got hot! Check out the brand new version of ColdFusion with the sparkling new developer IDE – ColdFusion Builder.
  • User Interfaces are a thing of the past now. Build User Experiences of tomorrow with Adobe Flash Catalyst. Quicker than ever!

Sign up for a Platinum Pass and get the award winning Adobe Flex Builder 3 Professional license worth USD 699 FREE!

Please find more details and register here

http://www.endtoend.in/ete2009/adobe/devsummit/mailer.html

Tuesday, July 21, 2009

Refactoring in ColdFusion Builder

First Let’s just discuss what is Refactoring the source code in general.

What is Refactoring ?

Refactoring code in a programs means, one cleans up the code to improve the understandability, maintainability of the source code by changing source code’s internal structure or design, but keeps the overall result of the program same.

So next question one would is “How do I Refactor my program’s source code ?

First thing, it must not be done manually by one, as it’s more prone to human errors. Refactoring has to be an automated process and it’s a feature of and provided by the most of the IDE.

ColdFusion Builder is the new IDE provided by Adobe for Rapid development of ColdFusion applications. ColdFusion builder allows user to Refactor their application source code.

So one may argue…What’s the big deal with ColdFusion Bulider? most of the IDEs provide refactoring…

The big deal here is that it’s very challenging task for a non-typed language to provide Refactoring feature. ColdFusion being a loosely typed language, it’s not that straight forward to implement Refactoring for ColdFusion Builder, but still an attempt has been made to provide this feature in ColdFusion Builder to make life easier for CF developers.

What should I refactor to improve the understandability or maintainability of my source code?

During the application development cycle, one may hurry to complete the application due to various reasons and hence may end up using the variable names, function names, filenames and many other source code constructs such that it becomes difficult to understand for other developer, making maintainability and understandability of the application difficult. In order to avoid such situation, developer should take corrective actions to Refactor the above mentioned code constructs for making it easier to comprehend for other developers.

What sub-features does ColdFusion Builder offer for Refactoring?

ColdFusion Builder provides the following sub-features in Refactoring.

CFC UDF Refactor

In the following component, let’s say…one want to rename test() function to test123(), so it means that all the valid instances of the test() function through out the application should get refactored, including the references in the same component but other functions referring it.



<cfcomponent namespace="Refactor.abc" extends="def.b" >
<cffunction name="test" access="remote">
<cfreturn 1>
</cffunction>
<!---Test 2 Method --->
<cffunction name="test2" access="remote">
<cfreturn test()>
</cffunction>
<!----Test Method 3 from def\b.cfc---->
<cffunction name="test3" access="remote">
<cfreturn foo1()>
</cffunction>
</cfcomponent>


So what should one do to achieve it? Just left click on the function name, and then Right click to open the Menu, as shown in the following screenshot.





Click on the Refactor->Rename menu item and it will open up a Input dialog as following,


Now, provide the “New Name” for the test method and once you do that Disabled Preview button is enabled. Notice that we are enforcing user to preview the changes being done by ColdFusion Builder. Reason being at certain places, CF can not determine if the instance has to be considered for refactoring or not and so in such cases, it’s upto user to decide if the unsure instances (unchecked) shown in the preview, has to be considered or not. If required user should check it before preceding by pressing “OK” button.

Notice that even the URLs in / tags, which are referring to this test() method are being considered for refactoring. Such URL references are possible to consider for refactoring only when the Server is registered with ColdFusion Builder and the URLs are very much valid and accessible, which otherwise is not possible.

Note: User can Undo the Refactored changes by pressing Cntrl+Z from keyboard.

So we have seen how to refactor an UDF in CFC. Similar way, we can also perform the following operations.

  • Refactor CFM UDF
  • Refactor CFC UDF
  • Refactor Funcion Local scope variables
  • Refactor Function Argument Names
  • Refactor the CFC Name
  • Refactor CFM Name
  • Refactor Custom Tags
  • Refactor CFQuery Names
  • Refactor Scoped Varaible names like This/Application/session etc.. variables.
  • Refactor UnScoped Global variables in a CFM/CFC.
  • Refactor Variables in Included and Includee file.
  • Refactor ORM CFC which should also get reflected in ORM Entity Methods.
  • Method Refactoring through – “Application Varaible Mappings” in CF Builder

Note: To refactor the CFM/CFC/CustomTags, Explore the Template thorough Project Navigator, Right Click on the Template and select Refactor->Rename menuitem, as shown in the following screenshot.


Note: File/Template Refactoring is allowed only for, CFM/CFC files. TXT files or any other types of files can not be refactored.

Method Refactoring using "Application Variable Mappings"

Assume a scenario where an Application variable is defined for a CFC Object as following.

<cfset Application.appVar = createObject("component","abc.AppCFM.a")>

And now, the CFC function called Method() is invoked as following in some other template
<cfset Application.appVar.Method()>


In such a case, While Refactoring the Method() function, If a Varaible mapping is created for the application variable, then the above invokation usage will be considered for Refactoring, otherwise it will be ignored.

To Create Application Variable mappings.... Right Click on the Project >Properties window>ColdFusion Variables Mappings>Click on New button>enter Variable name as "Application.appVar" and Mapped To as "abc.AppCFM.a", Click OK button.


References Search

Not that always one needs to refactor the Code, But there are times, when one only wants to see/find the references of the Methods/Varaibels/CF templates etc…

In such a case, one can use the References option in the Right Click Menu, as shown in the following screenshot.



Similar option is also available for Template search from Project navigator view.
Reference search results will be shown in the Search panel as shown below.



Wednesday, July 15, 2009

Enhanced Flash Remoting (CF9) Vs. Old Flash Remoting

One may wonder, what is this deal about in ColdFusion 9 for “Enhanced Flash Remoting”? Or One may also wonder what was wrong with Old Flash Remoting (CF8 style) that we needed to enhance Flash remoting in ColdFusion 9?


To find answers for these questions, let’s first explore, what was wrong with CF8 style flash remoting. Mainly there was one problem and that was the “Circular reference serialization-deserialization” bug.


This bug was long standing problem for Advanced CF-Flex developers who tried to send nested or related ActionScript Objects having circular reference to each other, over wire to ColdFusion from Flex Clients, resulting in following error.


[Flex]Exception when invoking service 'remoting-service': flex.messaging.Message

Exception: java.lang.StackOverflowError

.

.

.

Exception: flex.messaging.MessageException: java.lang.StackOverflowError

at coldfusion.flash.messaging.ColdFusionAdapter.getFlexError(ColdFusionA

dapter.java:361)

at coldfusion.flash.messaging.ColdFusionAdapter.invoke(ColdFusionAdapter

.java:273)

.
.

.


--> This Bug is fixed in ColdFusion 9 – Enhanced Flash Remoting feature. So Developers are no more blocked writing advanced Flex-CF Applications with having AS Objects with circular references.


Let’s discuss another advantage of using new Enhanced Flash Remoting. Fixing the circular reference bug wasn’t an easy task, many radical changes were required to be done to fix this issue and most of the ActionScript-CF datatype translation or serialization-deserialization process has to be re-written in many ways. This gave us the opportunity to improve the entire process, resulting in faster AS-CF datatype translation which made New Enhanced Flash Remoting faster many times against Old Flash Remoting.


--> A Significant Performance Boost for Flash Remoting.

  • Enhanced Flash Remoting is 6 -7 times faster against CF 8.0.1
  • Enhanced Flash Remoting is 10-11 times faster against CF 8.


So How did I measure this Performance Gain?


To measure this performance gain, I created a small Flex Application which will send an Actionscript Object to ColdFusion 9 and ColdFusion 9 will echo it back to Flex application. So making an entire server trip and back will give an appropriate idea about the serialization-deserialization process both ways.


The below Actionscript Object that I used for this purpose has most of the common datatypes of AS.


package com

{

[RemoteClass(alias="perf.DataSamples")]

public class DataSamples

{

public var firstname:String = "";

public var lastname:String = "";

public var city:String = "";

public var zip:uint;

public var email:String = "";

public var ContactNos:Object;

public var designation:String = "";

public var experience:int;

public var salary:Number;

public var CompaniesWorkedFor:Array;

public var dateOfBirth:Date;

public var IsMarried:Boolean;

public var Children:Object;

public function DataSamples()

{

}

}

}


As you observe that, this DataSample class has properties of varying datatypes like String / uint /int / Objects(CFC mapped Objects, Plain AS objects) / Number / Array (Indexed, Associative) / Dates / Boolean. Also observe that this DataSample AS class also maps with a ColdFusion server side CFC “perf\DataSamples.cfc”. So most common Flex app scenarios are being covered through this AS class.


I am assuming here that similar sort of AS object would broadly represent a Flex application’s Custom AS Class.

Now, so in what quantum or magnitude I should send this DataSample objects I should use to find out the performance difference between Enhanced Flash Remoting and Old Flash remoting. Sending a Few DataSample objects may not give a real idea about the performance gain, so in order to measure the real difference in speed, we have to magnify it by replicating a high traffic Flex application which sends DataSamples Objects around in the range of 10,000 – 50,000. See the following stat metrics that has been gathered in similar environments ( Win2k3 R2 + Intel Xeon CPU 2GHz + 2GB RAM) for ColdFusion 8 / ColdFusion 8.0.1 and ColdFusion 9.

No. of CFCs

Response Time

( Readings for Echo operation in ms )


ColdFusion 8

ColdFusion 9ColdFusion 8.0.1

10 K

14599, 14301, 13890, 14203, 13725

1278, 1297, 1285, 1266, 1250

7203, 7609, 7062, 7125, 7235

20 K

29484, 32531, 27188, 27219, 27600

2821, 2812, 2815, 2500, 2828, 2515, 2703, 2516

14328, 14672, 14375, 14437, 14523

30 K

41907, 41078, 41355, 41688

3969, 4032, 3765, 4031, 3719, 4031, 3718

21703, 22312, 22578, 22469

40 K

55032, 54782, 55392, 55189

5000, 5328, 5219, 5313, 5000, 5344

30625, 30641, 30516, 30629, 30593

50 K

70312, 69890, 70891, 70234

6562, 6281, 6500, 6297, 6578, 6297, 6265

42297, 41516, 39610, 39188, 38010

Each of the reading given in the metrics represents an average of 10-20 server cycles response time. Why I opted to it this way, instead of just taking 1 server cycle, is to get an average time which will be most nearer to the actual figure. For 10K/20K CFCs, average is for 20 server cycles, and for higher 30K-50K CFCs, average is for 10 server cycles.


So If you observe the stats, it suggest that ColdFusion 9 is significantly faster over CF8(10-11 times) and CF801(6-7 times).


A few Basics Questions One may have in mind…..


--> Does ColdFusion 9 also support Old Flash Remoting ?


Yes. It supports, CF8 style, “Old Flash Remoting” for backward compatibility purpose. As “Enhanced Flash Remoting” of ColdFusion 9 requires a few structural changes in the WEB-INF\flex\ XML configuration files at Channel as well as Destination level. By default ColdFusion 9 installation supports new Enhanced Flash Remoting.



--> What are these changes at Channel and Destination level in flex Configuration files from previous CF releases to CF9?


The following properties have been moved from Destination to Channel level. You need to move these properties under <channel-definition > --> <properites> --> <coldfusion> from your destinations.


For more details, refer Documentation, Changes in the XML configuration files for New Flash Remoting in ColdFusion 9.


<access>

<use-mappings>

<method-access-level>

</access>


<use-accessors>

<use-implicit-accessors>

</use-accessors>


<use-structs>

<property-case>

<force-cfc-lowercase>

<force-query-lowercase>

<force-struct-lowercase>

</property-case>

</use-structs>



--> So What happens, while migrating from previous CF installs to ColdFusion 9, if I just simply drop my old WEB-INF\flex XML configuration files, without above changes, over ColdFusion 9 installation?


With Old style XML Flex configuration files, it will continue to work but in this case ColdFusion 9, will use Old Flash Remoting and not the Enhanced Flash Remoting.

One must follow above suggested XML changes, in order to take advantages offered by Enhanced Flash Remoting.

Tuesday, July 14, 2009

ColdFusion 9 - AIR SQLite Offline Support

In this Article, I will be explaining about the new feature, AIR Offline Support, introduced in ColdFusion 9. This Article will try to cover, most of the aspects of the feature with Code snippets to simplify the subject.

Now, before explaining this feature I would like to cover a few basic questions which user may have in mind.


Is this a client side feature or server side feature?


This is mainly a client side feature which could be used for Flex based AIR applications. Browser based Flex applications can not take advantage of this feature as it needs client side SQLite DB which is offered only by AIR platform.

Also, There are a few ColdFusion Interfaces defined on server side, which user need to comply with while writing their CFC having “Fecth” and “Sync” methods.


Why Offline Support in ColdFusion 9 where as AIR also provides it?


One may argue that AIR provides Offline SQLite DB support, then why ColdFusion 9 is redoing it? To clarify on this, ColdFusion 9 is not redoing it, but rather making it more simplified by introducing an ActionScript persistence framework which could help in taking all the complexities and pain away from user to deal with Client side DB/Tables/SQL Queries etc...


Why should I use Offline feature of ColdFusion 9 ?


By using the ActionScript persistence framework introduced in ColdFusion 9, user doesnt need to create the client side DB Schema, Tables and also user doesn’t need to write even a Single line of SQLite Query to store/update/retrieve data from Offline DB. Isn’t it simplified ?


How can ColdFusion 9 Offline feature do it without writing Queries?


This ActionScript Persistence Framework, comes with many Metadata tags to assist user in defining their client side classes which should be mapped with Client side DB. See the few basic Metadata tags information in the following table.

MetaData Tags

Purpose

[Entity]

Specifies that instances of this class can be persisted to the SQLite database. This element is
required.

[Table( name = "tableName")]

The name of the SQLite table in which the object is to be stored. Defaults to the name of the

class.

[Id]

Precedes a field definition. Indicates that the field is a primary key in the table. For composite

keys, use Id tags on all the primary key fields.

[Column(name="name",

columnDefinition="TEXT INTEGER

FLOAT BOOLEAN VARCHACHAR",

nullable = true false, unique = true false ) ] ),

Specifies the SQLite database column that contains data for this field.

name Column name. If not specified, defaults to the property name.

columnDefinition The SQL Datatype to use for the column.

nullable Specifies whether a field can have a null value.

unique Specifies whether the value for each field must be unique within the

column.


This framework also offers Relationship Metadata tags, like [OneToOne],[OneToMany],[ManyToMany],[JoinTable],[JoinColumn],[InverseJoinColumn] which are used to define relationships between the AS classes, which is also being followed while creating Offline tables for these classes. Refer ColdFusion9 AIR Offline Documentation for more information on these Relationship metadata tags.


Let’s have a look at a Simple AIR Offline Application Example ….


Given is the Screenshot of the Application. Application has mainly 2 sections, top section is used for performing the CRUD operations and Bottom datagrid panel provides user to view the local SQLite data for Customer and Address tables. Also it provides 2 buttons for Fetching data from server and Syncing local data changes back to server.







This Application demonstrates working of two Objects, Customer and Address, having One-To-One relationship.


It also demonstrates concepts of CASCADING, LAZY Loading, FETCHing and PERSISTing Server data on client side SQLite DB.


CONFLICT management is also one of the important concept for Offline applications, as user may be working in offline mode for a long time and when user tries to sync the data back to server it may happen that those datasets are already updated or deleted by other clients.


Also on server side it uses, newly introduced feature of ColdFusion 9, ORM, for Fetch() and Sync() methods. To get to know more on ORM feature of ColdFusion 9 refer the documentation.


How to setup this example as a project ?


Download this application from below link.






-->After extracting the ZIP file, put “AIRIntegration” folder directly under your ColdFusion 9 wwwroot


-->Create a DataSource called ‘AIROffline’ in CF Admin on “AIRIntegration\

ServerSideDB_AIROfflineExample.mdb” using MS Access with Unicode as driver.


--> Import ‘CFAIROfflineCustomerManagerApp.zip’ as Flex Project into your Flex Builder.


--> Once Imported you may need to change ‘cfair.swc’ path from Project->Properties-> Flex build Path -> Library path. Adding this SWC file into your library path is very important in order to use AIR Offline feature of Coldfusion 9. You may also want to change your compiler arguments to set the right path for services-config.xml file.

--> Change the SyncManager CF Server credentials in application, as per your CF Server IP/Port/ContextRoot.

Following above steps should be good to go for launching this Application.


Let’s have a look at Client Side ActionScript Classes…


I have explained the constructs of the class by providing inline comments, so read through it.


Customer.as


package onetoone

{

[Bindable]

// corresponding Server side class

[RemoteClass(alias="AIRIntegration.customer")]

// This tag is required to create a client side Table for Class

[Entity]

// Optional. If table name is not provided, class name will be

//considered as default name for creating table

[Table(name=”Customer”)]

public class Customer

{

//Define PK for Offline “Customer” table, “cid” will be PK

[Id]

public var cid:int;

public var name:String;

// Defines OneToOne relationship with Address class

[OneToOne(cascadeType='ALL',fetchType="EAGER")]

// Foreign Key Column which will be referring to Address table

// name="add_id" --> FK Column Name

// referencedColumnName="aid" --> Refers to the Address Table PK

[JoinColumn(name="add_id",referencedColumnName="aid")]

public var address:Address;

}

}


Address.as


package onetoone

{

[Bindable]

[RemoteClass(alias="AIRIntegration.address")]

[Entity]

public class Address

{

[Id]

public var aid:int;

public var street:String;

}

}


Corresponding Server side ORM CFCs ….


customer.cfc : This ORM Cutomer CFC has one-to-one relationship with Address CFC, as it can be observed in the 3rd cfproperty defined.



<cfcomponent persistent="true">

<cfproperty name="cid" fieldtype="id" >

<cfproperty name="name" >

<cfproperty name="address" fieldType='one-to-one' CFC="address" fkcolumn='aid' cascade='all' lazy="false">

</cfcomponent>



address.cfc: This ORM Address CFC has no references back to Cutomer CFC it being a one directional relationship. Although it’s quite possible to have bidirectional relationship.



<cfcomponent persistent="true">

<cfproperty name="aid" fieldtype="id" >

<cfproperty name="street" >

</cfcomponent>



cusManger.cfc: This is the Manger CFC which AIR Offline app client interacts with. This Manger CFC will have to implement “CFIDE.AIR.ISyncManger”. This interface has declaration for SYNC method. The SYNC Method in the following code handles CONFLICT management as well part from persisting client data changes to server. It Uses ORM Entity methods to perform the CRUD operations.


These CRUD operations could also be done using normal but that would be not so clean way of writing SYNC method. Because Query approach will require query records sets to get translated into Objects before sending data to AIR Offline app client. And also vice versa, each and every property of AIR Client Objects needs to be accessed for performing CRUD operations.


Also Notice the ORMGetSession().merge() methods in SYNC method usage before calling EntitySave() / EntityDelete() methods. You may see following kind of error message if you are using Old Style (cf8) Remoting with AIR Offline applications having server side "Sync" method using ORM EntitySave()/EntityDelete() methods.


Error handling message: flex.messaging.MessageException: Unable to invoke CFC - a different object with the same identifier value was already associatedwith the session: [address#1]. Root cause :org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated withthe session: [address#1]


You may also encounter this error with new style (cf9) Remoting also but only for EntityDelete method.

Same above solution will apply to resolve this issue.



<cfcomponent implements="CFIDE.AIR.ISyncManager">

<!----Fetch method--->

<cffunction name="fetch" returnType="Array" access="remote">

<cfset cus = ArrayNew(1)>

<!----This ORM Method will load all data from Server Customer table and send it to AIR client ---->

<cfset cus = EntityLoad("customer")>

<cfreturn cus>

</cffunction>

<!----SYNC method, Sync Client data with Server and also handles Conflicts--->

<cffunction name="sync" returntype="any">

<cfargument name="operations" type="array" required="true">

<cfargument name="clientobjects" type="array" required="true">

<cfargument name="originalobjects" type="array" required="false">

<cfset conclits = ArrayNew(1)>

<cfset conflictcount = 1>

<cfloop index="i" from="1" to="#ArrayLen( operations )#">

<cfset operation = operations[i]>

<cfset clientobject = clientobjects[i]>

<cfset originalobject = originalobjects[i]>

<cfif operation eq "INSERT">

<cfset obj = ORMGetSession().merge(clientobject)>

<cfset EntitySave(obj)>

<cfelseif listfindnocase("UPDATE,DELETE",operation) neq 0>

<cfif isinstanceOf(originalobject,"customer")>

<cfset serverobject = EntityLoadByPK("customer",originalobject.getcid())>

<cfelseif isinstanceOf(originalobject,"address")>

<!---Ignoring Address object, as it is casceded with Customer Object, so while saving Custoemr, Address will also be saved,

If not Ignored, then It will result in Conflict, incase Cutomer and Address CFC relationship has lazy=fasle.

--->

<cfcontinue>

<!---<cfset serverobject = EntityLoadByPK("address",originalobject.getaid())>

<cflog text="AddressID: #originalobject.getaid()#">--->

<cfelse>

<cfthrow message="Invalid Object">

</cfif>

<cfif not isdefined('serverobject') >

<cflog text="CONFLICT::SERVER OBJECT NOT FOUND, RECORD MAY BE DELETED ALREADY">

<cfset conflict = CreateObject("component","CFIDE.AIR.conflict")>

<cfset conflict.clientobject = clientobject>

<cfset conflict.originalobject = originalobject>

<cfset conflict.operation = operation>

<cfset conflicts[conflictcount++] = conflict>

<cfcontinue>

</cfif>

<cfset isNotConflict = ObjectEquals(originalobject, serverobject)>

<cfif isNotConflict>

<cfif operation eq "UPDATE">

<cfdump var="#clientobject#" output="C:\clientobject.txt">

<cfset obj = ORMGetSession().merge(clientobject)>

<cfset EntitySave(obj)>

<cfelseif operation eq "DELETE">

<cfset obj = ORMGetSession().merge(originalobject)>

<cfset EntityDelete(obj)>

</cfif>

<cfelse><!----Conflict--->

<cflog text = "is a conflict">

<cfset conflict = CreateObject("component","CFIDE.AIR.conflict")>

<cfset conflict.serverobject = serverobject>

<cfset conflict.clientobject = clientobject>

<cfset conflict.originalobject = originalobject>

<cfset conflict.operation = operation>

<cfset conflicts[conflictcount++] = conflict>

<cfcontinue>

</cfif>

</cfif>

</cfloop>

<cfif conflictcount gt 1>

<cfreturn conflicts>

</cfif>

</cffunction>

</cfcomponent>



What is the Flow Of the client side AIR Application ?


It is upto developer to decided on the Offline application workflow depending upon the application requirements. But I am trying to present here a general approach which may be suitable for a large number of offline applications.

As soon as this example application is launched, it will first try to connect to server by creating an instance of SyncManger, in order to fetch the server data. See the following code snippets with inline comments provided.


private function init():void

{

// Provide Credentials for Server side Connection and CFC

syncmanager = new SyncManager();

syncmanager.cfPort = 8501;

syncmanager.cfServer = "localhost";

// Path of the Server side CFC having Sync/Fetch method, relative from CF webroot

syncmanager.syncCFC = "AIRIntegration.cusManager";

// THis handler will be called when any COnflict occures while writing back changes on serverside

syncmanager.addEventListener(ConflictEvent.CONFLICT, conflictHandler);

// Fetch Server side DB data onto Client SQLite DB while starting the App itself

var token:AsyncToken= syncmanager.fetch("fetch");

token.addResponder(new mx.rpc.Responder(fetchSuccess, fetchFault));

}


Once Server connection is established successfully it fetches the data on client side and stores it on local clientside SQLite DB by creating a DB, if already not created.


private function fetchSuccess(event:SyncResultEvent):void

{

var cus:Array = event.result as Array;

cusColl = new ArrayCollection(cus);

// Open a Session for the client side SQLite DB, It will create a //DB with Name “onetonesync.db” under user directory

dbFile = File.userDirectory.resolvePath("onetoonesync.db");

/*

Providing a Unique interger number in openSession method is required in order to create a unique database session, in order to avoid conflicts with other Applications.

*/

var sessiontoken:SessionToken =syncmanager.openSession(dbFile,017915);

sessiontoken.addResponder(new mx.rpc.Responder(connectSuccess,connectFault));

}

private function connectSuccess(event:SessionResultEvent):void

{

session = event.sessionToken.session;

if(cusColl.length > 0)

{

// This operation will save/update fetched data into AIR SQLite DB

var savetoken:SessionToken = session.saveUpdateCache(cusColl);

savetoken.addResponder(new mx.rpc.Responder(saveCacheSuccess, savefault));

}

else

{

Alert.show("No data available from Server to save on local DB, Grid will be attempted to load with local DB Data if any available");

updateGrid();

}

}



So now, user has local data available to work with in offline mode. This data will be available even in case of server is unreachable or network outage.

User has all the liberty to perform CRUD operation by Adding new records, by Editing existing Records or by Deleting them.



// This Method will be used for Insert / Update operations

private function SaveLocal():void

{

cus = new Customer();

cus.cid = int(cusId.text);

cus.name = cusName.text;

add = new Address();

add.aid = int(AddId.text);

add.street = AddStreet.text;

cus.address = add;

/*

INSERT the new Records, this will be first saveed in client side SQLite DB, only on Commit operation this will be saved this new records in Server side DB. Notice that we are only saving Customer here, this operation will also save the binded Address Object also, as both the entities are CASCADED inside Customer Class

*/

var savetoken:SessionToken = session.saveUpdate(cus);

savetoken.addResponder(new mx.rpc.Responder(savesuccess, savefault));

}

// This Method will be used for Delete operations

private function DeleteLocal():void

{

cus = new Customer();

cus.cid = int(cusId.text);

cus.name = cusName.text;

add = new Address();

add.aid = int(AddId.text);

add.street = AddStreet.text;

cus.address = add;

var savetoken:SessionToken = session.remove(cus);

savetoken.addResponder(new mx.rpc.Responder(removeSuccess, removeFault));

}



At any point in time if user feels like getting fresh data from Server, he can do so by pressing the “Fetch Data Server” button. This operation will override the Updated/deleted data changes by user. Newly inserted records on local DB table will have no impact by Fetch data operation. So it makes sense to perform this operation while only when you changes are Synced with Server.


Once after performing the required data changes, user needs to write back this data on server. It can be done by performing “Commit” operation by pressing “Commit/Sync local data to Server” button.



private function commit():void

{

/*

So far, we have performed Insert/Update/Delete operation on Customer/Address entities on client side SQLite DB, Now let's send them to Server by performing COMMIT Operation

*/

var committoken:SessionToken = session.commit();

committoken.addResponder(new mx.rpc.Responder(commitSuccess, commitFault));

}



Now, while Syncing back data on Server, it may happen that user has stale data that he was working on OR User is updating a record that is already deleted from Server. In this case, Server CFC will throw back an array of Conflicts back to client, informing client about the latest server data copy. There will be a Conflict Event on client and eventually Conflict Handler will be called. Now, it is upto user to Accept / Ignore this Server changes. Incase, user wants to Accpets these changes he can do so as following.


One more Important aspect of Conflict handler that one need to know is, even incase of conflict, the Commit Success event will be fired. So, you will see that ConflictHandler as well as CommitSuccess Handlers both will be called. This happens because commit success event is fired when data changes from client reaches to server successfully. Now, this data gets written on server DB or not, it doesn’t wait for this. And hence, if there are conflicts here, we fire another Conflict event.



private function conflictHandler(event:ConflictEvent):void

{

Alert.show("conflict man!");

var conflicts:ArrayCollection = event.result as ArrayCollection;

// Accept Server data and write it to client side SQLite DB

var token:SessionToken = session.keepAllServerObjects(conflicts);

token.addResponder(new mx.rpc.Responder(conflictSuccess, conflictFault));

}