19 October 2009
The samples discussed in this article presume the reader possesses a high-level understanding of Adobe technologies (such as Flex and AIR) and of Adobe products (such as ColdFusion and LiveCycle Data Services ES).
Advanced
In this article, I will discuss how to use Adobe technologies to build an enterprise micro-blogging solution. My intent is to demonstrate that a full-fledged, enterprise-capable solution can be built using solely Adobe tools. Such a solution can overshadow existing comparable solutions on many levels, including security, convenience within the enterprise, and integration with other technologies.
This article does not explain step-by-step how to build a micro-blogging solution, but rather presents the framework and Adobe technologies that you can use to construct your own.
Note: For related information, you may also want to watch our recorded MAX 2009 session on Adobe TV: Vibes, Twitter, and enterprise microblogging (60:00).
There are several building blocks that make it easier to build a killer enterprise micro-blogging solution: data management, ORM, rock-solid enterprise scalability, and a cross-platform RIA desktop experience. Adobe ColdFusion 9, Adobe LiveCycle Data Services ES, and Adobe AIR combine to provide them all.
ColdFusion 9 provides a solid and powerful application server. With the addition of Hibernate Object Relational Mapping (ORM) support, using ColdFusion as the service layer cuts the code needed to handle all the CRUD from 100+ lines across several ColdFusion Components (CFCs) to just a few lines.
ColdFusion 9 also comes with Flex/Flash remoting and integration, allowing the client Adobe AIR application to perform a mix of data service subscriptions and remoting calls to retrieve data. The ORM implementation in ColdFusion 9 simplifies object mapping. A prime use case for a micro-blogging solution is the concept of Groups and Users. Defining a Group persistent object with a one-to-many mapping to Users makes modifying the Group membership easy. Modifying the Users array contained in the Group object and calling EntitySave('Group') will handle all of the needed database transactions, including insert, delete, and modify operations.
Using the Adobe LiveCycle Data Services ES (2.6.1) data management capabilities and RTMP (Real Time Messaging Protocol) channel provides both a real-time subscriber/publisher model and a scalable enterprise model. With this technology, the system maintains persistent RTMP connections with the clients to provide real-time message delivery. LiveCycle Data Services ES in combination with AIR provides off-line synchronization support, allowing users to store messages locally for searching when offline.
A huge part of any enterprise solution is cross-platform support. With both Mac and Linux gaining ground on Windows among workplace desktops, the most useful clients are deployable across all three operating systems (not to mention the various versions of each). Not only does Adobe AIR meet this objective, but the auto-update framework built into Adobe AIR also makes updating and managing application versions simple.
This section describes the ColdFusion and LiveCycle Data Services ES set-up, configuration, and application files.
Please refer to Adobe ColdFusion 9 Help for details on installing ColdFusion 9, and then follow the steps outlined for integrating LiveCycle Data Services ES 2.6.1 on ColdFusion 8 (it is the same process for ColdFusion 9).
After you have installed ColdFusion 9 and LiveCycle Data Services ES, you're ready to get started.
To use the data management capabilities in LiveCycle Data Services ES, you have to define a service destination in the data-management-config.xml file located in your {ColdFusionRoot}/wwwroot/WEB-INF/flex directory. Refer to the following example of a service destination:
<destination id="messageService">
<adapter ref="coldfusion-dao"/>
<channels>
<channel ref="cf-rtmp"/>
</channels>
<properties>
<component>components.demo.MessageAssembler</component>
<scope>request</scope>
<metadata>
<identity property="message_id"/>
</metadata>
<network>
</network>
<server>
<fill-method>
<use-fill-contains>false</use-fill-contains>
<auto-refresh>true</auto-refresh>
<ordered>false</ordered>
</fill-method>
</server>
</properties>
</destination>
Now consider the properties defined in it, from the top.
<destination id=…>
This specifies the destination with an id attribute. You use this id to reference the destination.
<adapter ref=…>
This refers to the adapter being used to serialize the data. Because this example uses integrated LiveCycle Data Services and ColdFusion, this property is set to coldfusion-dao. Adapters are defined in the first section of the data-management-config.xml file. There are other types of adapters (including Java and ActionScript object); for more information see Understanding data management adapters.
<component>components.demo.MessageAssembler</component>
This property specifies the CFC that LiveCycle Data Services ES will use to implement the CRUD functions (see Step 3: Create MessageAssembler.cfc for details). Essentially, this Assembler implements six basic functions: fill, doCreate, doUpdate, doDelete, sync, and get. When a collection that LiveCycle Data Services ES is managing (that is, monitoring for updates, new items, deletes, and so on) changes, it will look to this Assembler and call the necessary functions.
<channels>
<channel ref=…>
</channels>
This property defines the channel that will be used to communicate with the destination. These channels are defined in the services-config.xml file (found in the same folder as data-management-config.xml). This example uses cf-rtmp; make sure it is uncommented in the services-config.xml file.
<scope> </scope>
This defines the scope in which the request lives; possible values are application or request.
<metadata>
<identity property="message_id"/>
</metadata>
This property uniquely identifies the items in the database. In this example, message_id is the primary key reference in the database.
<server>
<fill-method>
…
</server>
These are parameters to be passed when calling the fill method; the values used in the code are the defaults. For more details refer to the LiveCycleData Services documentation.
To take advantage of the ORM capabilities in ColdFusion 9there are a few things that need to be configured, including Application.cfc, theentity CFCs, and MessageAssembler.cfc.
Add the following lines to your Application.cfc file:
<cfset this.name = "Demo Message Service" />
<cfset this.ormEnabled = "true" />
<cfset this.ormSettings = {
Dialect="MySQLwithInnoDB",useDBForMapping=true,savemapping=false,logSQL=true
} />
<cfset this.datasource = "Demo" />
This code does three things:
Dialect. This code lets ORM know that it will be using a MySQL database to persist the data.Demo. Data sources are configured in the ColdFusion Administrator; refer to the ColdFusion documentation for more details. In this example, there are two entity objects corresponding to two entity CFCs, Message.cfc and Dig.cfc. Messages are the main entities that contain the information about the message being sent such as the user, content, and posting date. Dig entities are entries of users who like or dislike the message, similar to a rating. One message can have multiple Dig entries related to it; you use ORM to define this relationship. These entities (which are similar to POJOs in the Java world) are simple value objects; to make them ORM enabled you need to add certain parameters.
In the Message.cfc, add the following parameters:
<cfcomponent persistent="true"
table="message" entityname="Message">
Persistent="true" enables ORM functionality on this entity.Table="message" maps the Entity to the corresponding database table.EntityName="Message" defines the entity name used in ORM functions.The Message entity defines several properties:
<cfproperty name="message_id"
fieldtype="id" generator="identity"
generated="always" unsavedvalue="0" />
This message_id property is a special property known as an identifier or id property. You specify fieldtype="id" to map a property to the primary key in the table. The values for generator and generated indicate how this property is generated. In this case, it is mapped to the primary key column in the Message table, so the MySQL database will always generate a value for it when it is written. (For more information, see the ColdFusion 9 documentation.) Finally, unsavedvalue="0" tells ORM how to determine if this entity has been saved to the database. When the code tells ORM to save a Message with a message_id value of 0, ORM will know to create a new entry instead of trying to update an existing one.
<cfproperty name="content" />
<cfproperty name="user_id" />
These properties are pretty standard; the name of the property corresponds to a column in the database table. If you want to map different column names to properties, you can add column="myContentColumnHere" in the <cfproperty> tag.
Finally, in the Message.cfc file there is a <cfproperty> tag with a one-to-many mapping.
<cfproperty remotingFetch="true"
name="digs"
cfc="Dig"
fieldtype="one-to-many"
collectiontype="array"
fkcolumn="message_id"
lazy="false" cascade="all" notnull="true"/>
This adds an array property to the Message entity containingDig entities. This relationship is well described in the ORM section of the ColdFusion9 documentation. Note that the remotingFetch propertymust be set to true for this, or else this property will not be returnedwith Flex remoting calls.
There are six functions in the Assembler component forLiveCycle Data Services: sync, fill, get, doCreate, doUpdate,and doDelete.
The fill method is called to get the collection.Clients execute the fill method on a data service, which triggersLiveCycle Data Services ES to maintain a managed collection on the server side.When new objects are added, LiveCycle Data Services ES will determine if anyclient subscribed with fill parameters will need to be notified of this update.If one or more clients are supposed to see this item (based on the fillparameters), LiveCycle Data Services ES will dispatch an event to them andupdate them accordingly. If a client's fill parameters don't match the criteriafor viewing, it will not be notified.
Note: When two or more users perform a fill on a dataservice with the same fill parameters, LiveCycle Data Services ES will onlyneed to maintain one managed collection along with a reference for each userthat needs to be notified. This is handy information to have when buildingapplications with server-side memory consumption in mind.
The doCreate, doUpdate, and doDelete methods(as their names imply), create, update, and delete items. For example, if auser who is subscribed to a data service adds an item (for example, a message) from his or her managedcollection on the client side, LiveCycle Data Services ES calls the doCreate method and passes the item that was created.
LiveCycle Data Services ES comes with three SWC files that you'll need to import to your project: airfds.swc, fds.swc, and fds_rb.swc. Personally, I like to copy these three SWC files to the libs folder in my AIR project.
Connecting to a data service from an AIR client is pretty easy after a few setup steps.
First, you create value objects (in this case, Message.as and Dig.as) in ActionScript, which have values that map to the corresponding CFC entities server side. Setting the [Managed] tag on the class indicates that this is an object that is managed by LiveCycle Data Services ES. The [RemoteClass(alias=..)] matches up the ActionScript object with the ColdFusion entity, so values are serialized correctly and the objects are easy to work with on the client side.
[Managed]
[RemoteClass(alias="components.demo.Message")]
Public class Message
{
…
}
Next, you create the actual data service. The data servicerequires a ChannelSet, which it will use to establish the connection to theserver. The code to create it (for this article's server-sideconfiguration) is as follows:
//global vars:
private var myDataService:DataService;
private var myFillArrayCollection = new
ArrayCollection();
//onCreationCompleteFunction:
//create an RTMPChannel
var myRTMPChannel:RTMPChannel = new RTMPChannel(
"cf-rtmp","rtmp://myserver.hi:2048")
//RTMPChannel requires the ID of the RTMP channel as defined in
the services-config.xml and the full name of your server, plus the port that
the rtmp channel is listening on, also defined in services-config.xml
//create a new ChannelSet and add your newly created RTMP channel
to it.
var myChannelSet:ChannelSet = new ChannelSet();
myChannelSet.addChannel( myRTMPChannel );
//Now we create the actual DataService and assign the channelset
to it
myDataService = new DataService( "messageService"
)
// messageService is the ID of the destination we setup in the
data-management-config.xml earlier
myDataService.channelSet = myChannelSet;
myDataService.addEventListener(ResultEvent.RESULT,
onDataServiceResult);// add a 'onDataServiceResult' function in later in the
code, or comment this out.
myDataService.fill( myFillArrayCollection ); //performs the
'fill' method defined in the MessageAssembler.cfc on the given DataService and
returns the results into the 'myFillArrayCollection'
If all goes well, you should be able to put a break in your onDataServiceResult function and see the contents of myFillArrayCollection, which will be a series of Message objects with Dig objects in some of them.
Because your myFillArrayCollection was the target of the myDataService fill function it becomes a managed collection. Any item changes (adds, updates, deletes) to this array collection will trigger the corresponding LiveCycle Data Services ES function defined in the Assembler. For example, when the client creates a new Message object, sets some values in it, and then calls myFillArrayCollection.addItem(myNewMessage), it will trigger the doCreate function in the Assembler (which writes the object to the database using the ORM function EntitySave) and then update all clients that are also subscribed to this data service.
From here, you can add some custom item renders on a List control and you'll have a very rough (and simple) real-time message collaboration tool!
This mix of Adobe technologies provides an enterprise stack that you can use to build a quality, comprehensive, enterprise micro-blogging solution. This enterprise stack enables the ongoing enhancement of both back-end services and front-end clients to enable rapid development of enterprise social networking solutions.
I encourage you to assemble your own solution to get a better understanding of the new features that ColdFusion 9 has to offer, the power of LiveCycle Data Services ES 2.6.1, and the convenience and cross-platform capabilities of AIR. When you do, I'm confident that you'll reduce twentieth-century communication within your enterprise and increase streamlined collaboration.
Also be sure to watch our recorded MAX 2009 session on Adobe TV: Vibes, Twitter, and enterprise microblogging (60:00).
Tutorials & Samples |