At work, we’re investigating using ColdFusion Event Gateways to handle certain complex types of communication between our Flex user interfaces and ColdFusion, so yesterday I jumped on Google and started researching and ran into some roadblocks. However, after some monkeying around and more poring over of documentation and articles, I finally got a basic example working.
As usual, now that I’ve discovered how to set up a somewhat advanced feature of a platform, I’m sharing the knowledge in a comprehensive article. The documentation available for getting ColdFusion and Flex to communicate via event gateways was scattered, incomplete, or incomprehensible. In many of the articles, there were a lot of words, but little or no code, which does not help developers at all. Don’t tell me how it works, SHOW me how it works.
The listener component is the ColdFusion code that will receive any message sent from your Flex client via the DataServicesMessaging gateway type in your ColdFusion admin (more on that later). The basic structure is simple – just need one method named onIncomingMessage() in your component.
Create a file called InterceptFlex.cfc somewhere in your webroot and put the following code in it.
<cfcomponent output="false">
<cffunction name="onIncomingMessage" returntype="any">
<cfargument name="event" type="struct" required="true" />
</cffunction>
</cfcomponent>
Now you need to go to your ColdFusion Administrator so that you can create an event gateway that specifies that any message coming in on a certain destination will be sent to the InterceptFlex component.
There is a destination already set up for you in the \WEB-INF\flex\services-config.xml file (or \WEB-INF\flex\messaging-config.xml file if you are running BlazeDS) called ColdFusionGateway, and we’re just going to use that for this example.
You just need to make one change for this sample application to work. Open up the XML file and find the ColdFusionGateway destination. In the <properties> block add the following server property:
<properties>
<server>
<durable>false</durable>
<allow-subtopics>true</allow-subtopics>
</server>
...
</properties>
Now, go to the Gateway Instances section of your ColdFusion Administrator and start creating a gateway.
This application is a slight modification from the code provided in the Adobe article Introduction to the Flex Message Service, which I highly recommend you read if you’re new to Flex Messaging.
Create a new Flex application called Chat and paste this code into the Chat.mxml file. This code will connect to the ColdFusionGateway destination and send the message object to ColdFusion. ColdFusion, in turn, uses the event gateway instance we set up to send that object to the onIncomingMessage() method of the InterceptFlex.cfc component.
<?xml version="1.0" encoding="iso-8859-1"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"
pageTitle="Simple Flex Chat" creationComplete="createChat()">
<mx:Script>
<![CDATA[
import mx.messaging.Consumer;
import mx.messaging.Producer;
import mx.messaging.events.MessageAckEvent;
import mx.messaging.events.MessageFaultEvent;
import mx.messaging.events.MessageEvent;
import mx.messaging.messages.AcknowledgeMessage;
import mx.messaging.messages.AsyncMessage;
import mx.utils.ObjectUtil;
private var chatPublisher:Producer;
private var chatSubscriber:Consumer;
private function createChat():void
{
chatPublisher = new Producer();
chatPublisher.addEventListener(MessageFaultEvent.FAULT, onProducerFault);
chatPublisher.destination = "ColdFusionGateway";
chatSubscriber = new Consumer();
chatSubscriber.addEventListener(MessageAckEvent.ACKNOWLEDGE, onConsumerAck);
chatSubscriber.addEventListener(MessageEvent.MESSAGE, receiveChatMessage);
chatSubscriber.destination = "ColdFusionGateway";
chatSubscriber.subtopic = "simpleChat";
chatSubscriber.subscribe();
}
private function onProducerFault(faultEvent:MessageFaultEvent):void
{
output.text += "[Error: " + faultEvent.message.toString() + "]\n";
}
private function onConsumerAck(ackEvent:MessageAckEvent):void
{
output.text += "[Got ack for subscribe or unsubscribe operation]\n";
}
// Note: these are the event-handling methods from above, now moved into the separate source file:
private function sendChatMessage():void
{
var msg:AsyncMessage = new AsyncMessage();
msg.body = input.text;
msg.headers["username"] = "Me";
msg.headers["gatewayid"] = "test";
chatPublisher.subtopic = "simpleChat";
chatPublisher.send(msg);
input.text = "";
}
private function receiveChatMessage(msgEvent:MessageEvent):void
{
var msg:AsyncMessage = AsyncMessage(msgEvent.message);
output.text += msg.headers["username"] + ": " + msg.body + "\n";
}
]]>
</mx:Script>
<mx:Panel title="Simple Flex Chat">
<mx:TextArea id="output" width="500" height="220" />
<mx:TextInput id="input" width="500" enter="sendChatMessage()" />
<mx:ControlBar horizontalAlign="center" width="500">
<mx:Button id="clearBtn" label="Clear" click="output.text =''" />
</mx:ControlBar>
</mx:Panel>
</mx:Application>
Now that ColdFusion has received the message, we’re simply going to respond back. You can enhance this to do anything you wish – send out emails, update database tables, log messages – but for now we’re just going to send a message back that let’s the Flex client know that the mechanism works.
<cfcomponent output="false">
<cffunction name="onIncomingMessage" returntype="any">
<cfargument name="event" type="struct" required="true" />
<cfscript>
x = structNew();
x.body = "hello right back at ya";
x.destination = "ColdFusionGateway";
x.headers = structNew();
x.headers['username'] = "System";
x.headers['DSSubtopic'] = "simpleChat";
x.lowercasekeys = "yes";
</cfscript>
<cfreturn x />
</cffunction>
</cfcomponent>
One of those esoteric details that took me forever to find out was how to apply a subtopic to a message in ColdFusion. In Flex, it’s absurdly simply, you simply say message.subtopic = “myTopic”;, but in ColdFusion, you have to set a header key named DSSubtopic with the topic name (see above).
To be safe, restart your ColdFusion instance, then fire up the simple Flex chat app and type in a message. After a few seconds, you will receive a message from System in the history box.
32 Responses for "Tutorial: Flex and ColdFusion Communication via Event Gateways"
Steve, what’s the advantage of Flex-CF communication through the Event Gateway vs the more traditional method with RemoteObject and CFCs? What are the issues that have driven you to look for this solution?
Since we work with medical billing records, we deal with large data sets regularly and complex database applications. Unfortunately, certain processes can take far too long to execute over an RemoteObject call, which results (in certain situations) in timeouts and errors. We’re looking at using queues to manage this instead so that the application server can process complex tasks without keeping a channel open for minutes at a time.
so this technic let me built a chat without blazeDS ?
No, dl, this technique uses the messaging mechanism that BlazeDS (or LCDS) provides to your JEE application server. The ColdFusion gateway is connecting to a messaging destination which is only available when you have a messaging system installed.
I starting to shift away from lcds and I have started playing with blazed ds. After looking over your tutorial and trying implement it. I ran into this error.
08/18 14:45:53 Error [Thread-15] – Error invoking CFC for gateway test: Unable to find the Flex adapter for destination ColdFusionGateway in the RMI registry on localhost:1099. {GATEWAYTYPE={DataServicesMessaging},ORIGINATORID={E6E6D6F7-DB0E-B9BC-8186-0D1EA68DF769},DATA={{clientid={E6E6D6F7-DB0E-B9BC-8186-0D1EA68DF769},timetolive={0},body={qweqwe},destination={ColdFusionGateway},correlationid={},timestamp={Tue Aug 18 14:45:53 MST 2009},messageid={C5830619-5DFB-7980-2D3E-2F792CEBCA76},headers={{DSId={E6E6BCE2-9C1D-9929-4F47-8AA69EF58372},DSEndpoint={cf-polling-amf},DSSubtopic={simpleChat},username={Me},gatewayid={test}}}}},GATEWAYID={test}}
Any help would be greatly appreciated.
Thanks! this finally opened the door for me and it works with your example.
I assume that when we want a chat that works for 2 or more people we remove the cfscript element in the CFC file and return the EVENT from cfargument. For example:
When I try this I get the following error about the ‘body’ entry in CF Admin:
Error invoking CFC for gateway test: Unable to locate the body entry in the outgoing message structure. {ORIGINATORID={D6842865-F092-BC51-C116-A91D7E9442F5},DATA={{headers={{username={Me0.2707098610699177},DSId={D6821B7E-F191-64E1-54BE-AC9937545944},gatewayid={test},DSEndpoint={cf-polling-amf},DSSubtopic={simpleChat}}},destination={ColdFusionGateway},messageid={B71975F2-F4AC-CEA8-C938-11257ACA1B58},timestamp={Thu Oct 01 13:28:39 EDT 2009},correlationid={},clientid={D6842865-F092-BC51-C116-A91D7E9442F5},body={yo},timetolive={0}}},GATEWAYID={test},GATEWAYTYPE={DataServicesMessaging}}. You must include a body entry in messages for this gateway.
As you can see there is a BODY entry “body={yo}” how do I get this to return properly?
oops.. the above comment didn’t allow me to show you the “cfreturn event” code for InterceptFlex.cfc. Hope you got the idea.
I love it when I fix my problem 2 minutes after I ask.
I modified your cfscript to send back the data collected in the Flex app:
x = structNew();
x.body = event.data.body;
x.destination = “ColdFusionGateway”;
x.headers = structNew();
x.headers['username'] = event.data.headers['username'];
x.headers['DSSubtopic'] = “simpleChat”;
x.lowercasekeys = “yes”;
I hope you can point me in the right direction…
I’ve been a ColdFusion developer for about 5 years, and can do a lot of cool stuff with jQuery and alike, but time has come for me to have to write my first Flex app, and I’m hoping you might have a few suggestions.
I’m doing research on if it’s even possible for me to do what I need. I’m building an app to manage scores for sporting events, and some things like the leader boards, really need to be refreshing in real time. So as new scores come in, they should immediately be reflected on all leader boards, ideally with some animation or highlight that indicates a score just changed. Now the closest thing I’ve seen to what I need to do were all those CNN, Fox, CNBC apps during the last presidential elections, where as results were coming in the data was automatically pushed to all the connected clients. I don’t even know how that works conceptually, is it the server somehow pushing the data to the Flex clients? Cause I don’t want every Flex client to have to keep hitting the server every couple of seconds querying for changes like a web page would have to.
Do I even need to use Flex to do this? Can LiveCycle be used with just JavaScript/ColdFusion somehow to do this.
Any help, suggestions, examples are highly appreciated.
Thanks,
-Roman
Hi Roman. Hopefully I can answer your question adequately.
>> is it the server somehow pushing the data to the Flex clients?
Possibly. Using LCDS you can actually implement true push services to clients. Using messaging (available in BlazeDS for free), you simulate push by having each client subscribe to a message queue. However, this is simply another form of polling but less resource intensive.
>> Do I even need to use Flex to do this?
You don’t need Flex specifically, but you it does enable messaging whereas using HTML/JS you would have to write your own polling mechanism in Javascript which is not as reliable or scalable.
>> Can LiveCycle be used with just JavaScript/ColdFusion somehow to do this?
Technically yes, but it would defeat the purpose of using LCDS.
LCDS uses a specific protocol from Adobe called Real Time Messaging Protocol which creates a persistent connection between the server and client.
BlazeDS does not use this, but it does utilize the AMF protocol to poll the server while subscribing to messages. Both features are superior to an AJAX call using plain-text request/response mechanisms.
I hope that provides you with some starting points.
Thanks for posting this. It’s been really hard for me to find information about messaging. I’m stuck though. Can you post an example of the services-config file? I’m not sure I did that part right. My gateway starts up, but the flex app always throws an error saying that the destination doesn’t exist.
I tried this tutorial on CF9 with Flex in place and was able to get only the ACK notification. Everything else seems to disappear. The send works but the receive never gets anything.
I followed the tutorial piece by piece but I think I am missing a key bit.
@Justin: There’s nothing different about the service-config.xml file. It’s the one right out of the box. What version of Flex are you using?
@Jeff: If the ACK works then the communication channel is properly working – obviously. Perhaps the problem is in the Event Gateway. When you look at the Event Gateway via CF Admin, does it acknowledge that message are incoming?
More specifically, are the IN/OUT columns still at 0 or have they incremented?
I ran the app and the IN increments with each send but the OUT remains at 0. Sounds like the message is spinning off to buffer heaven but I don’t know why.
Just for drill, I should let you know I am using CF9 with its built in BlazeDS. I don’t know if that makes a difference.
I haven’t given up on this:
I added a CFLOG in the InterceptFlex.cfc that shows it is receiving the message properly but the call still shows the same thing in the eventgateway.log:
Error invoking CFC for gateway SimpleMessaging: Unable to find the Flex adapter for destination ColdFusionGateway in the RMI registry on localhost:1099. {GATEWAYTYPE={DataServicesMessaging},ORIGINATORID={B49196B6-F00D-EBA5-8DA6-F142CAB89F49},DATA={{clientid={B49196B6-F00D-EBA5-8DA6-F142CAB89F49},timetolive={0},body={hello },destination={ColdFusionGateway},correlationid={},timestamp={Sun Jan 24 13:11:31 CST 2010},messageid={4D542A74-C224-93E2-9A43-61BEFB134DF1},headers={{DSId={B4915A34-371E-B230-0123-E0D3FE395900},DSEndpoint={cf-polling-amf},DSSubtopic={simpleChat},username={Me},gatewayid={SimpleMessaging}}}}},GATEWAYID={SimpleMessaging}}. The Flex adapter may not be running or the destination may be incorrect.
I am at a loss.
I am still wrestling with this and had a thought late last night.
Does this example depend on how ColdFusion was installed? I am using the CF developer edition installed as an EAR file with JRun4.
Nope. ColdFusion 8 came with LCDS Lite installed and ColdFusion 9 comes with BlazeDS installed. If you are using either one of those versions, you could implement this right out of the box.
Then I am having some kind of issue I don’t see. I have followed your instructions to the letter and it still tells me that the destination is not found yet I can see where the message is coming in properly and being passed to the CFC. It is when I try to pass it back that the problem occurs.
What is “it” in your last comment? Flex or ColdFusion?
It’s when I try to pass the message back to Flex from ColdFusion. The it is the message.
I’ve tried and SendGatewayMessage(“test”, x). Neither worked.
In that last message the page edited out the “cfreturn x” CF tag.
I also failed to note that the webroot of the installation is htdocs in Apache web server.
Jeff, I am working on the same thing and having exactly the same problem, using stock CF9 install with blaze ds. I added a sendGatewayMessage to the cfc and now the output count started incrementing on the cfgateway. However, still nothing coming back to flex. I tried taking out the subtopic stuff but that didnt help. I am going to add a CFLOG and see what I get.
That’s exactly what I am getting with the SendgatewayMessage call.
Keep me posted on what you find from the CFLOG.
I got mine to work. The error is gone. Im not 100% sure what I changed, but I was playing around in WEB_INF\flex\messaging_config.xml and I uncommented the property localhost. I did a few other things that I dont think were signficant. One was I defined my channel set in code instead of taking it from a config, meaning the app didnt need a services_config.xml reference in compiler settings. I also made a copy of the default destination and called it MyGateway, so I could customize settings.
I still have some issues left. I cant get subtopics to work (I had commented out subtopics to start with), and my recieveChat event on the flex side is getting called twice for every chat msg, not sure why.
But at least I am getting a round trip message and no error.
@Jeff Regan & @Gordon K
The error message you are getting from “it” is that you are missing a destination or the destination is incorrectly configured. Destinations are configured manually in the messaging-config.xml file.
Be aware :
x.headers['DSSubtopic'] = “simpleChat”;
DSSubtopic is case sensitive. You have to call it in this fashion or ColdFusion/Flex will upper case the header value and make it inaccessible.
Steve,
Got a question – when sending an outgoing message from the gateway, how do i ensure that the message goes only to a specific client? In my situation, my flex app needs to receive messages of server actions completed, so its not two-way.
Jeff
Hey Jeff, check out this other article. Might provide some ideas for you.
http://www.fusioncube.net/index.php/application-and-client-specific-messaging-in-flex
Jeff Regan of the problem solved?
I’m having the same problem.
Creating new project – FLEX & CF
Hi there
I am in the process of creating a new project in Flash Builder 4.
I have given the following information
Project Name – SBMS
Application – Web – runs in Adobe Flash Player
Use default SDK (Flex 4)
Server Technology
Application server type: ColdFusion
Use remote object access
Then selecting – ColdFusion Flash Remoting
Note: The computer I am creating this project on is running Apache and ColdFusion 9 (Standard)
Apache is running in the following location:
c:\Program Files\Apache\
c:\Program Files\Apache\htdocs\CFIDE
Server location – should I select Standalone or Deploy to J2EE Server
Use default location for local ColdFusion Server is currently checked (but option below is greyed out
Use built in CF web server is not checked but the web root is currently showing as:
Web Root: c:\ColdFusion9\wwwroot\WEB-INF
Root URL: http://127.0.0.1
Compiled flex application location
Output folder
c:\ColdFusion9\wwwroot\WEB-INF\sbms-debug
Its the first time I’m trying to do this so any feedback would be greatly appreciated
Leave a reply