AJAX Longpolling with ColdFusion and BlazeDS - Getting set up

I've spent some of my week this week fighting with JavaScript, BlazeDS and ColdFusion to get a working model for some ExtJS functionality that I'm currently building at work.

One of several pieces of functionality we'd like is to have is real time notifications of workflow changes. The way it was described was "we want to push alerts to the users".

I decided to have a look at how we actually addressed this "problem". We didn't really need to "push" alerts to users, so the solution was traditional polling or long polling.

Traditional polling will hit Apache and ColdFusion via a timed ajax call over and over. Any "messages" that are sent to a client will wait on the server until the request is made.

Long polling opens a connection to the server and keeps that connection open until a timeout limit is reached and then reconnect. If a "message" is made available for the client, then the open connection will send it to the client immediately.

After reading the Best of CF9 Entry from Marko Simic on Ray Camden's blog and talking to a bunch of people, but specifically João Fernandes I decided to go with long polling using BlazeDS.

If you don't know what BlazeDS is, its the default messaging server used in ColdFusion 9, in place of Live Cycle Data Services. Given that I basically needed a messaging service between ColdFusion and ExtJS it seems logical that I should use this, particularly as it has the ability to create long poll connections.

As with all the thing i seem to be doing at the minute, they are actually pretty simple, but there's no concise idiots guide for the likes of me to be able to put these things together. Hopefully this blog post will help others.

There are a number of things that we are going to use and need to know in order to get started. Firstly, you cannot simply create a javascript long polling connection to BlazeDS. This has to be done through a bridge mechanism. Fortunately, there is a Flex-AJAX Bridge available for just this purpose.

We need a service channel definition in the services-config.xml and a ColdFusion event gateway.

We'll have an HTML/Javascript interface that will sit on the browser. This will include the Flex-Ajax Bridge.

On the server side we'll have BlazeDS handling the messaging and ColdFusion Event Gateways handling the messages that are sent.

This is kind of how I visualise how everything fits together.

Stephen's visualisation of how the elements of long polling fit together

Hopefully this diagram will make some kind of sense later on when all the pieces of code and technology are put together.

Ok, so lets get started with the two easiest bits of set up. The event gateway and the service channel.

If you've looked at Marko's Best of CF9 entry, you'll have seen in the INSTALL text that he has a bit of config that you need to insert into the services-config.xml file on your ColdFusion Server. This is the service channel and we'll be inserting the exact same piece of config. (I copied it from there - thanks Marko ;) )

Find services-config.xml under the Flex folder in your ColdFusion Server. I always use Multi Server installs and I always expand the cfusion.ear file out to folders, so on my local blog server I can find the flex folder here : C:\JRun4\servers\blog\cfusion-ear\cfusion-war\WEB-INF\flex

Open up the service-config.xml file and find the section. In this section insert the following channel definition :

view plain print about
1<channel-definition id="longpolling-amf" class="mx.messaging.channels.AMFChannel">
2 <endpoint uri="http://{server.name}:{server.port}{context.root}/flex2gateway/cfamflongpolling" class="coldfusion.flash.messaging.CFAMFEndPoint"/>
3 <properties>
4      <!--no-cache response headers on HEEPS-based endpoints-->
5                <add-no-cache-headers>false</add-no-cache-headers>
6                <!--
7                Enabling of the small message removes those from the header and only
8                passes the minimum that Flex needs to communicate with the server.
9                If you need to pass information via the header in
10                BlazeDS or LiveCycle just add this to your channel defintion
11                -->

12                <serialization>
13                    <enable-small-messages>false</enable-small-messages>
14                </serialization>
15                
16                <polling-enabled>true</polling-enabled>
17
18                <client-wait-interval-millis>1</client-wait-interval-millis>
19
20                <!--polling-interval-millis is the time interval between polling requests. Since we no longer need to pace the requests, we could safely set the interval to 0.-->
21                <polling-interval-millis>0</polling-interval-millis>
22
23                <!--dictates how long the server should wait before returning a polling request. The default is 0. By setting it to -1, we are telling it to wait indefinitely until a message is to be routed to the client.-->
24                <wait-interval-millis>120000</wait-interval-millis>
25
26                <!--max-waiting-poll-requests caps the number of long polling clients. Since the server is not ackowleging right away during long polling, each client hogs one server thread. Once the cap is reached, any new clients fall back to simple polling clients.-->
27                <max-waiting-poll-requests>100</max-waiting-poll-requests>                 
28                
29 </properties>
30 </channel-definition>

This is the BlazeDS channel that we'll be connecting too. The comments in there should help you understand what its doing. The important part to understand is that the wait-interval-millis is how long a connection will stay open for before BlazeDS drops the connection. This is what will allow us to create a messaging connection that will remain open.

For now I'm manually creating this channel and endpoint in the services-config.xml. Later I want to remove this and dynamically create an end point, so that we don't have to do any manual configuration and for one other reason I'll come to later.

Next go into the ColdFusion administrator, find the the event gateways section and the Gateway instances under that. Add a new data services messaging gateway :

ColdFusion Event Gateway for Polling

In this case I've just called it myGateway and I've pointed it at an empty cfc called gateway. This CFC will handle the messages that are sent from the browser to the server.

The last bit of set up, and the end of this blog post, is the initial set up of the Flex-AJAX Bridge.

The bridge is made up of 2 javascript files and a swf. The swf does actually exist you have to compile this yourself. The javascript files and the actionscript files can be found in the download of the source for BlazeDS or from the SVN repository here : http://opensource.adobe.com/svn/opensource/blazeds/branches/3.x/resources/fds-ajax-bridge/

There are also instructions on how to compile the bridge in the readme.txt file with the actionscript and javascript files. You may find that when run the compile with the command line given in the readme.txt file it will throw an error about not knowing what the context root is. If you do add "-context-root /" to the end of the command line, or replace the "/" with your context root if its different eg. "cfusion" is a possibility.

This compilation is the second reason why I would like to make the channels/endpoints dynamic. One of the attributes of the compile points to the services-config.xml file. If you change the services-config.xml file you will need to recompile the bridge swf. By compiling the bridge against a standard services-config.xml and dynamically generating the endpoint this will negate the need to recompile the bridge when ever you need a new endpoint.

So now we've got a message channel/endpoint, an event gateway, an empty event handler and our Flex-AJAX bridge. Just to conclude this blog post create an basic index.cfm file with your standard html head and body. Include the two Flex-Ajax Bridge javascript files in the head of the page. At the foot of the body insert :

view plain print about
1<script type="text/javascript">
2 // load the blazeds bridge
3FDMSLibrary.load("./blazeds/FDMSBridge.swf",initPolling);
4</script>

This will load the bridge swf that you compile previously. Note : The load function does a document.write() of a bunch of HTML to insert the swf into the page. I found that if you try to run this "onReady" or at the head of the page it would lock up the processing of the rest of the page. It really needs a rewrite to be a bit more clever than simply injecting the object/embed html into page where ever this is called. Again something for later down the line, probably as an Ext.JS object of some kind.

Lastly, before I fall asleep at my laptop, back up in the head of your page, create an empty javascript function called "initPolling".

I've attached a rar file with this initial bit of code, as well as the bridge javascript and my compiled FDMSBridge.swf. Whether you'll get any use out my bridge swf is really down to your set up.

TweetBacks
Comments
Could something like this be used to push song lyrics out to viewers watching a video church service? I'd love to build a tool to do that which would not require flash. Would need to update line by line as the song progresses.
# Posted By Kenny | 1/29/10 12:06 PM
I'm not sure that you could be that accurate with providing the lines of lyrics alongside the video.

While messages sent by ColdFusion to the event gateway are sent relatively quickly you can't guarantee that they will appear on the user's computer at exactly at the time that it would be needed there in the kind of scenario that you're suggesting.

You would probably be better looking into something like subtitling (http://www.internetsubtitling.com) that would provide titles to the video exactly at the time that they are needed.

If you were to do some kind of live feed, you could perhaps push lyrics for complete songs on an adhoc basis, but even then I think this is perhaps not the solution that you need.
# Posted By Stephen Moretti | 1/29/10 2:54 PM
Whats the performance like for the event gateways? Do they still work properly in high load scenarios?
# Posted By Faisal Abid | 6/24/10 3:13 PM
Faisal,

I believe so. To be honest I've yet to build or use anything in a high volume environment. These blog posts are as much a learning process as they are passing on what I have learned.

A few months back I did have a couple of sources that provided information on the number of connection for long polling versus the number of connection using traditional polling and apache. As I remember, the level of performance and number of connections was an order of magnitude greater for blazeds vs apache. (note this is hearsay and only what I remember from way back when)
# Posted By Stephen Moretti | 6/24/10 4:17 PM
hi there.

thanks for the tips, and this blog post! do you know if a flex front end is NECESSARY? or, could this be a simple web page, and use javascript to display things?

thanks!
# Posted By tony weeg | 11/2/10 1:42 AM
Hi Tony,

The articles I've written are all about using javascript to build applications with BlazeDS and ColdFusion in the back.

The only bit of Flex you need is the FABridge swf, which provides the bridge between javascript and BlazeDS.

Hope that makes it clearer
# Posted By Stephen Moretti | 11/2/10 8:05 AM