remoteObject() and Cold Fusion
I’ve recently started using Adobe Flex, and so far I really love it. Since I’m unable to design my way out of a wet paper bag, having pretty little components available like the datagrid has made me very happy.
Today i’m going to talk about my new friend remoteObject(), and since I am primarily a ColdFusion developer, i’ll be discussing specifially how to use it within a CF application. Those of you using other server side languages may want to stick it out, if for nothing more just to see how beautifully Flex can separate your view from your model. As far as the Flex side of things, it’s pretty similar between platforms anyhow. In this tutorial, I will show how to use remoteObject() to connect to a ‘user’ object on the server, and then display the results from this object in a flex datagrid.
First things first… if you are a ColdFusion developer and you are not familiar
with CFCs (Cold Fusion Components), stop here… do NOT pass go… do NOT collect
$200. You’ll need CFCs to really take advantage of what remoteObject is doing,
so if you do not know what they are or have never used them, read about them
here, and come back later.
If you are already familiar with CFCs, you will need this one: user.cfc for this tutorial.
What is remote object and how does it compare to httpService?
remoteObject() is exactly what it sounds like. It is a function used within Flex to access server side objects written in languages like ColdFusion, PHP, Ruby, or .Net. Different from httpService, the coolest thing about remoteObject() is that it can literally return an object back into Flex from any of these platforms (and more). remoteObject() is a better alternative to Flex’s httpService. When httpService is used within Flex, XML is returned to the Flex application. When remoteObject() is used, a tiny binary format called ‘AMF’ is returned. AMF is basically an Array of Arrays. Because of the size of the AMF data in comparison to the XML returned by httpService, remoteObject() is the faster of the two methods for getting data into your Flex application. XML parsing also has a lot of overhead within any platform, and sometimes your data is not stored in XML so you’re needing to parse it both on the server object as well as within Flex, creating more work for yourself along the way. Using remoteObject() at least with CF, you are literally able to pass Flex the result of a query as an object without having to transform your query into XML before you do. We’re not just talking about a small difference in speed between the two either. We’re talking 4 to 10 times as fast.
Let’s get started!
Ok… now that you know what remoteObject() is … let’s have a look at our user.cfc … we’re going to be working with the ‘Retrieve’ method:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <cffunction name="retrieve"> <cfargument name="id" default="" required="false"> <cfargument name="dsn" default="" required="true"> <cfquery name="usersQuery" datasource="#arguments.dsn#"> Select * from users <cfif #arguments.id# GT ""> Where user_id = #arguments.id# </cfif> </cfquery> <cfreturn usersQuery /> </cffunction> |
This user.retrieve() method will return a query object that is the result of the ‘usersQuery’. If you were to access this from ColdFusion, you would instantiate the cfc, call the retrieve method, and dump the result:
1 2 3 4 5 | <cfscript> user = createObject("component", "user"); listUsers = user.retrieve(); </cfscript> <cfdump var="listUsers"> |
Accessing a CFC using remoteObject involves a bit of setup, but once it’s done… it’s done, and everything moves a lot quicker from that point forward:
1) add a ‘destination’ for ColdFusion within your remoteing-config.xml. You
need to add the following inside the
your flex application’s root at /WEB-INF/flex/remoting-config.xml. If you don’t
have this file there already, you should find one within your ColdFusion 7.02
installation here: /CfusionMX7/wwwroot/WEB-INF/flex. If it is not found there,
it is probably found inline within services-config.xml. From Adobe’s site: “An
RPC service destination is the object or service that you connect to using an
<mx:RemoteObject>, <mx:WebService>, or <mx:HTTPService> tag
or the corresponding ActionScript API. ” It basically is an alias that points
to your RPC service, which is in our case… Cold Fusion server.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <destination id="ColdFusion"> <channels> <channel ref="my-cfamf"/> </channels> <properties> <source>*</source> <!-- define the resolution rules and access level of the cfc being invoked --> <access> <!-- Use the ColdFusion mappings to find CFCs, by default only CFC files under your webroot can be found. --> <use-mappings>true</use-mappings> <!-- allow "public and remote" or just "remote" methods to be invoked --> <method-access-level>remote</method-access-level> </access> <property-case> <!-- cfc property names --> <force-cfc-lowercase>false</force-cfc-lowercase> <!-- Query column names --> <force-query-lowercase>false</force-query-lowercase> <!-- struct keys --> <force-struct-lowercase>false</force-struct-lowercase> </property-case> </properties> </destination> |
2) You will need to setup a channel for ‘my-cfamf’ within the <channels>
tag. Adobe defines ‘channels’: "Flex Data Services transports messages
to and from service destinations over message channels that are part of the
Flex messaging system. You can pair any type of service with any type of channel."
I won’t get into all of the message channel formats that are supported,
but will define the two main ones that are used.
AMF: Channel that you use to send AMF-encoded messages to
the AMF endpoint, which supports AMF requests and responses sent over HTTP.
When using this channel for publish-subscribe messaging, you usually set the
polling property to true in the channel definition. You can also configure the
polling interval in the channel definition. The following example shows an AMF
channel definition:
1 2 3 | <channel-definition id="samples-amf" type="mx.messaging.channels.AMFChannel"> <endpoint uri="http://{server.name}:8100/myapp/messagebroker/ amf" type="flex.messaging.endpoints.AmfEndpoint"/> </channel-definition> |
HTTP: Channel that you use to connect to the HTTP endpoint,
which supports HTTP requests and responses. This channel uses a text-based (XML)
message format. The following example shows an HTTP channel definition:
1 | <channel-definition id="my-http" class="mx.messaging.channels.HTTPChannel"> <endpoint uri="http://{server.name}:8100/dev/messagebroker/http" class="flex.messaging.endpoints.HTTPEndpoint"/> </channel-definition> |
Your channel definition can either be referenced as ’services-config.xml’ from within remoting-config.xml or can be placed there inline. Here is mine:
1 2 3 4 5 6 7 8 9 | <channel-definition id="my-cfamf" class="mx.messaging.channels.AMFChannel"> <endpoint uri="http://{server.name}:{server.port}{context.root}/flex2gateway/" class="flex.messaging.endpoints.AMFEndpoint"/> <properties> <polling-enabled>false</polling-enabled> <serialization> <instantiate-types>false</instantiate-types> </serialization> </properties> </channel-definition> |
Your endpoint is really all you need to be concerned with here, and you can change the uri to point to where-ever your flex gateway is setup.
If you like, you can also setup your channel within your Flex application at run time by instantiating a ChannelSet object containing a Channel object, and assigning the ChannelSet to a service component. This way you can dynamically assign the endpointUrl:
1 2 3 4 5 6 7 8 | // Create a ChannelSet. var cs:ChannelSet = new ChannelSet(); // Create a Channel. var customChannel:Channel = new AMFChannel("my-polling-amf", endpointUrl); // Add the Channel to the ChannelSet. cs.addChannel(customChannel); // Assign the ChannelSet to a RemoteObject instance. myRemoteObject.channelSet = cs; |
<whew!> now that all of that setup is completed, it’s really simple to
connect to your user.cfc using remoteObject():
1 2 3 | <mx:RemoteObject id="userRetrieveRO" destination="ColdFusion" source="cfcs.user"> <mx:method name="retrieve" /> </mx:RemoteObject> |
And it’s just as easy to get that data from your remoteObject into a datagrid:
1 2 3 4 5 6 7 8 | <mx:DataGrid id="userGrid" width="100%" height="100%" dataProvider="{userRetrieveRO}"> <mx:columns> <mx:DataGridColumn dataField="firstName" headerText="First Name"/> <mx:DataGridColumn dataField="lastName" headerText="Last Name"/> <mx:DataGridColumn dataField="userName" headerText="UserName"/> <mx:DataGridColumn dataField="email" headerText="Email"/> </mx:columns> </mx:DataGrid> |
Note the ‘dataProvider’ argument… this should be the ‘id’ of your remoteObject(). That’s it! What it’s doing here is pretty simple. First the remoteObject instantiates the user.retrieve() object on the server, which returns the result of a query (a list of users) back as a query object. Finally, the DataGrid looks to userRetrieveRO as it’s dataProvider, and it expects an array of arrays… which is what AMF is handing it.






















Wikinomics: How Mass Collaboration Changes Everything
Adobe Flex 3: Training from the Source
Breaking Out of the Web Browser with Adobe AIR
August 2nd, 2007 at 12:50 am
[...] more -> [...]