1 Preface
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.
2 Creating a ColdFusion Listener Component
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.
InterceptFlex.cfc
<cfcomponent output="false">
<cffunction name="onIncomingMessage" returntype="any">
<cfargument name="event" type="struct" required="true" />
</cffunction>
</cfcomponent>
3 Setting Up Your Event Gateway
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.
3.1 Destinations
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>
3.2 Gateway Setup
Now, go to the Gateway Instances section of your ColdFusion Administrator and start creating a gateway.
- The gateway ID can be anything, and you can just call it “test” for now.
- Select DataServicesMessaging as the type.
- The CFC path is the physical path to your InterceptFlex.cfc file you created.
- the configuration file is located in the \WEB-INF\cfusion\gateway\config\ directory, and you can use the one already set up named flex-messaging-gateway.cfg. So find that file and enter the path here.
- Click the Add Gateway Instance button.
- Start the gateway instance you just created.
4 Sending Messages From Flex
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>
5 Respond to the Flex Client
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).
6 Conclusion
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.