Introduction to BlazeDS
Introduction to BlazeDS
by John Mason
6/13/2008
Presentation Slides: blazeDS-slides.pdf
Code Examples: blazeDS-code.zip
Adobe Connect: 8/14/08 Recording
An updated set of example files using BlazeDS and ColdFusion with Flex and Javascript is now available, blazeDSExamples.zip. These were the examples I showed at the 2009 cfObjective Conference.
Introduction to BlazeDS
There has been a lot of discussion since Adobe released BlazeDS, an open source messaging system that contains some of the features found in LiveCycle Date Services (LCDS). In this article, I will briefly try to explain what BlazeDS is and, also more importantly understand what it is not. Also, we will explore how it relates to LCDS. Once you have a lay of the land, we will demonstrate how you can use BlazeDS with a ColdFusion Event Gateway in a simple but useful example.
Messaging Patterns
Several messaging patterns have been developed over the years. Servers
and applications have to find ways to communicate with each other. The
most common pattern that we as web developers work with is a pull (or
request/response) method. A client?s browser requests a web page and
the server responses with a HTML formatted document, which the browser
processes for the client to see. The browser is essentially initiating
the communication and is ?pulling? the information it needs from the
server. Fairly simple, but take a look at all the progress that has
been made off this simple idea. Naturally, if there is a ?pull?
methodology then there has to be a ?push?. Streaming is the most common
example of a ?push? technology. The client doesn?t know what
information it needs, so it can?t directly request it. However, it can
subscribe to a channel that has the information it needs. Think of your
TV, when you flip to a news channel. You don?t know what the news is,
but you do know that the channel has the information you are looking
for. The news station is publishing its content over the channel to you
and anybody else tuned in. Once again, fairly simple, but there is a
lot you can do with this.
HTTP GET and POST are examples of a pull pattern. We work with these all the time. Web Services are also pulls. The server in these cases provides us with a standardized XML/SOAP formatted response. Additionally, Remote Procedure Calls (RPC) serve as pulls. Typically, an object on one system is serialized (turned into a binary message) that can be transported to another system. For example, with Flex?s RemoteObjects, we can invoke a ColdFusion CFC method as if it was an ActionScript object. We can also transport data as objects. In the Flex/Flash/AIR world, serialization is done with Action Message Format (AMF), which Adobe has developed over the years. The specification for AMF was recently published by Adobe in Dec 2007. When we go over BlazeDS, you can have the messages formatted as HTTP responses, SOAP messages or AMF messages.
Streaming is an example of a push pattern. We subscribe to a stream and the server sends information to us over the wire. The HTTP protocol has, since version 1.1, had specifications for streaming. AMF streaming simply borrows from this.
BlazeDS
BlazeDS
is a messaging service infrastructure built on Java, which contains
pull patterns, pull patterns that have the look and feel of push and a
couple of push (streaming) patterns. It also has a proxy service that
allows for Flex applications to access services outside their domain.
You can use the AMF serialization with these patterns to provide speed
and performance. However, BlazeDS does not have the Real Time Messaging
Protocol (RTMP) that you find in LCDS. This is important because the
HTTP and AMF streaming that BlazeDS provides is completely undependable
for most real world applications. You need RTMP, and more specifically
RTMP tunneling, to make a dependable push pattern work. Hence the
confusion with BlazeDS and whether or not it has push technology. RTMP
also has better scaling. Depending on the Java Virtual Machine?s (JVM)
configuration and memory heap size, you can provide service up to a
couple hundred clients with BlazeDS. With LCDS, you should be able to
run that into the thousands.
What?s in a Name?
Another point of confusion is the naming of these products. LiveCycle
ES (Enterprise Suite) has several products integrated in it. It is
truly a product suite with services like PDF generation, digital
signing and data services. The data services component is called,
naturally, LiveCycle DS (or LCDS). BlazeDS is essentially LCDS minus
RTMP. LCDS provides dependable streaming, message queuing, data paging
(lazy loading) and client-server synchronization. There is also another
version called LiveCycle DS Community Edition which is really BlazeDS
with a paid Adobe support subscription. And finally, there is LiveCycle
Express which is a single-CPU version of LCDS that can be installed
with ColdFusion 8. Finally, there is the old Flex Data Services, FDS,
which people ask about which is today LCDS.
Enterpise Service Bus (ESB)
Several people have noted that with LCDS and BlazeDS, we are really
looking at an Enterprise Service Bus architecture. So what is an ESB
and why could this be something very interesting to use?
Typically, clients and services communicate directly with each other.
In order for this to work, the clients have to know several things, like the location of the services and the method of communication. If the services move, then the clients have to be modified to properly take note of the change. Take a Flex application that reads data from a web service. If the web service location changes, the Flex application may very likely have to be updated. This can be time consuming and messy to deal with.
By injecting a service bus between the clients and the service providers, we can decouple things. Now the clients only have to know how to connect to the service bus. They may not even really know what the service providers are or where they are coming from. This is called service location transparency. It also provides a clear service-oriented architecture (SOA) where you have three distinct players: service provider, service broker and service requestor. If you see the benefits of MVC architecture in your coding, SOA is a similar idea.
So when looking at BlazeDS and LCDS, thinking of ESB may be very helpful and can show the reason way you as a ColdFusion or Flex developer may want to use it.
Installing BlazeDS with ColdFusion
The first thing to take note of is that ColdFusion 8 can be installed
with a single-processor version of LCDS called LiveCycle Express. You
may want to seriously consider using that instead since you can do RTMP
streaming with it. If you want to use BlazeDS, I would encourage you to
integrate it with your ColdFusion installation so it is running off the
same JVM. It is easier to use and setup. Follow the installation guide
at http://opensource.adobe.com/wiki/display/blazeds/Installation+Guide
You can install BlazeDS on CF 7, but it has to be version 7.0.2 or
higher. The rest of this article is going to assume you have BlazeDS
installed and integrated with ColdFusion 8.
Messaging Framework
BlazeDS has three basic frameworks for handling communication: remote,
proxy and messaging. The remote is for calling things like remote
objects. Proxy allows Flex applications to be able to call services
outside their domain without needing a crossdomain.xml policy file.
We?re not going to review these two aspects. The messaging service is
the one we will focus on.
The message framework in BlazeDS is an asynchronous message pattern where senders (producers) of messages are not programmed to send their messages to specific receivers (consumers), but rather to a destination which handles the routing, filtering and forwarding of messages. Another name for this framework is subscribe/publish or producer/consumer which is a part of a larger architecture called message-oriented middleware (MOM). Do not get confused with client/server and producer/consumer. The client can be a producer or a consumer, or both. The same holds true with the server. The client/server distinction is at the physical level. The producer/consumer is at the logical level.
The consumers and producers communicate through the service destination via channels.
The channels are accessed via adapters. The adapters are like a network adapter on your computer. If you look at your messaging-config.xml configuration file, you will see three basic adapters: cfGateway, ActionScript and JMS. As you might suspect, you need the cfGateway adapter to have Coldfusion to access a destination with an event gateway. The same is true for the ActionScript Adapter which you need for a Flex application to communicate. The nice thing about adapters is that the Coldfusion event gateway doesn?t need to know or worry with the type of channel it is using. You can also create your own adapters to expand the capabilities of BlazeDS.
The channel will format the message and deliver to the endpoint. The endpoint translates the message into a Java object that the message broker inside the service destination can understand. The message broker deals with the routing and queuing of the messages.
BlazeDS gives us several channel types:
HTTP
AMF
AMF with polling
AMF with long polling
HTTP streaming
AMF streaming
There are nonsecure and secure via SSL/TLS versions of all these channels. The HTTP channels will send data as a non-binary text message. The AMF will be binary. So for the performance and handling, I would highly encourage you to use the AMF channels. Now you could use the streaming channels to do a push strategy, but because of a variety of issues dealing with proxy servers, reverse proxies and firewalls that can delay or disrupt a stream, you may find these to be highly unreliable. But if the streaming can?t be established, it can be made to fall back to a polling channel. The standard HTTP and AMF types are for the typical request/response calls like webservices, etc.
Polling is really a pull strategy but has the look and feel of a server side push. The load on the server is greater than streaming but is far more dependable since we do not have RTMP tunneling available with BlazeDS.
Standard polling is very simple. The subscriber will send a series of requests to the service. The service in turn will either send an acknowledgement back or a message if there is one in the queue.
As you send, the client and server are continuously chatting with each other to keep this going which is not an efficient use of resources. It also could feel slow to the user depending on the timing of each request cycle. You may have the cycle run every 5 seconds, so the user could see a delay from sending a message and receiving it.
The long polling tries to solve these problems.
When the client sends a request to the service, the service waits until a message is in queue to send a response. This decreases the chatter and greatly increases the responsiveness. There are still several opening and closing of connections, but long polling will look and feel a lot like a server push. Frankly, your users are not going to see the difference. It?s not going to scale as well as streaming, but in many cases that may not be an issue.
Just to wrap this up, streaming is similar to long polling in that the client makes a connection and the server then never closes the connection. It actually sends small pings over the wire to keep the line active with the client. While the stream is active, messages are sent over the wire.
Running BlazeDS with a ColdFusion Event Gateway
So
now that we know what BlazeDS is and how it runs, we can set up a
simple example with a ColdFusion Event Gateway and see how it can be
used. For our example, let?s say we have a website throwing several
errors that we are trying to track down and debug. We use cferror to
catch these exceptions and mail them to us, but this is slow and
frustrating. We would prefer to see these errors in real-time. With
BlazeDS, we can do this fairly easily. So instead of sending these
errors via email, we will send the errors through an event gateway to
BlazeDS that will forward them to a Flex or AIR application that we
have that shows us the errors in real-time. Think of this as being very
similar to a Linux Tail function.
First, we need to create the BlazeDS destination with its associated channel and endpoint. We open our messaging-config.xml file and simply put in a new destination node called ?siteerrors?.
The destination will use the adapters that are available and the default channels. You could do this, but we will take a further step to tell the destination to listen for our ColdFusion gateway and to use long polling first, and then fall back to standard polling if that doesn?t work.
<properties>
<gatewayid>errorsgateway</gatewayid>
</properties>
<channels>
<channel ref="cf-longpolling-amf"/>
<channel ref="cf-polling-amf"/>
</channels>
</destination>
Now the channel endpoints are typically defined in the services-config.xml file. You may or may not have these in place.
<channel-definition id="cf-longpolling-amf" class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://{server.name}:{server.port}/{context.root}/flex2gateway/cfamflongpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>true</polling-enabled>
<polling-interval-seconds>5</polling-interval-seconds>
<wait-interval-millis>60000</wait-interval-millis>
<client-wait-interval-millis>1</client-wait-interval-millis>
<max-waiting-poll-requests>200</max-waiting-poll-requests>
</properties>
</channel-definition>
<channel-definition id="cf-polling-amf" class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://{server.name}:{server.port}{context.root}/flex2gateway/cfamfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>true</polling-enabled>
<polling-interval-seconds>3</polling-interval-seconds>
<serialization>
<instantiate-types>false</instantiate-types>
</serialization>
</properties>
</channel-definition>
The URL for these endpoints can vary. With Tomcat, your URL will have messagebroker instead of flex2gateway. The channel id and the last part of the endpoint URL can be anything you like as long as it?s unique. The channel properties are fairly easy to understand. They deal with the polling times, timeouts, etc. All we have to do is restart ColdFusion and we have an active BlazeDS destination service. As an important note, you can start your ColdFusion service via command line to see if the destination loads up correctly without errors. It also is handy to see any problems as clients try to publish to it.
Now we need a ColdFusion Event Gateway to link up our destination to ColdFusion.
Since we are just publishing from ColdFusion, our errorsgateway.cfc is going to be really simple..
<cfcomponent output="false">
</cfcomponent>
Note:
If we wanted the gateway to be a consumer, then we would have a method
in our CFC called ?onIncomingMessage? with a single argument variable
that is a structure.
When we add this gateway in, it should auto start. Be patient, it may take a minute. Once it is up and running, we can publish messages from ColdFusion into BlazeDS with the SendGatewayMessage() function. So we can put this code into a cferror page or inside an onError method in an application.cfc or in a cfcatch block to send these error messages to our Flex client.
For the sake of argument, we'll say we are using this code inside a cfcatch block to alert us to a failed login attempt.
<cfset body = structNew()/>
<cfset body.detail = "A failed login detected with #form.username# as a username from #cgi.remote_addr#"/>
<cfset body.message = "Failed Login"/>
<cfset body.type = "Information"/>
<cfset message = StructNew()/>
<cfset message.body = body/>
<cfset message.Destination = "siteerrors"/>
<cfset SendGatewayMessage("errorsgateway", message)/>
The message is a structure which contains the location of the destination and the message body which in this case is also a structure, but it can be whatever you like.
Now we have the destination service and the publisher. But we need a Flex application to subscribe and read the messages being sent. In Flex Builder, we create a new Flex project. Don?t bother with the server technology wizard they provide in the setup. For simplicity, we?ll just point the builder arguments to our services-config.xml file. When the project is established, right click and go to the project?s ?Properties?, then ?Flex Compiler?. Under additional compiler arguments, we will add a couple of parameters.
First, a ?services? variable which will point to our services-config.xml file. This tells Flex how to properly talk to BlazeDS. The ?context-root? variable is also needed to successfully compile. Now it is important to note that this setup can also be done inside of Actionscript, which is better way to handle this. The method we are using here is for demonstration purposes only.
In Flex the tag used to consume messages sent via BlazeDS is mx:Consumer. In the following code, we will use this tag to subscribe and consume the service feed. The messages will populate an ArrayCollection which in turn will be the dataProvider for our DataGrid. If you click on an item in the DataGrid, then the bottom TextArea will display the DETAIL node of our message structure.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.messaging.events.MessageEvent;
import mx.messaging.messages.AsyncMessage;
import mx.messaging.messages.IMessage;
import mx.collections.ArrayCollection;
import mx.events.ListEvent;
[Bindable]
public var messages:ArrayCollection = new ArrayCollection;
public function init():void{
consumer.subscribe();
}
private function messageHandler(message:IMessage):void{
//The zero index makes certain the newest message is on top
messages.addItemAt(message.body,0);
}
]]>
</mx:Script>
<mx:Consumer id="consumer" destination="siteerrors" message="messageHandler(event.message)"/>
<mx:Panel title="Errors" width="100%" height="100%">
<mx:DataGrid id="errorslist" width="100%" dataProvider="{messages}">
<mx:columns>
<mx:DataGridColumn width="100" dataField="TYPE" headerText="Type" />
<mx:DataGridColumn dataField="MESSAGE" headerText="Message" />
</mx:columns>
</mx:DataGrid>
<mx:TextArea id="msgDetails" width="100%" height="100%" htmlText="{errorslist.selectedItem.DETAIL}"/>
</mx:Panel>
</mx:Application>
When you run this Flex application, you should see something like the following..
As errors are detected by ColdFusion, they will be published and set over to destination service which in turn will send those messages to your Flex application. We now have a have a very simple but handy tool to see site errors as they are happening in real-time. We don?t have to hit refresh on the browser or anything. The polling will run in the background and the messages will display as they come over the wire. You could give this application to your support staff or programmers so they can see in these errors as well which would help diagnosis problems people encounter with your ColdFusion application.
If you wanted the Flex client to publish messages, you could use the tag.
<mx:Producer id="producer" destination="siteerrors"/>
Then you can format the same message structure and publish it to the service.
private function send():void{
var message:IMessage = new AsyncMessage();
message.body.DETAIL = "Detail of the message";
message.body.MESSAGE = "Error message name";
message.body.TYPE = "Information";
producer.send(message);
}
A couple of things to note, ColdFusion is not case sensitive where Flex is. ColdFusion uppercases the variable names in the background to run properly in its Java environment. That can throw you when you try to call a variable like message.body.detail instead of message.body.DETAIL Also, remember the message can be just about anything. I used a structure here with three nodes.
Concluding Thoughts
A true push strategy with BlazeDS is not really practical for most
applications, but you can simulate it fairly well. Once again, your
users are very unlikely to know the difference. If you really want to
use RTMP then I would encourage you to either obtain the full version
of LiveCycle DS or use the LiveCycle Express Edition that comes with
ColdFusion 8. There are also a few third-party open source projects
that either re-engineer the RTMP protocol or provide data services
through other means.
However, BlazeDS does provide a lot of things for you to use and I hope this article encourages you to give it a run. Adobe is fairly new to the open source community. It?s up to us to show that the community will provide feedback and support for this. Since it was open source you are starting to see developers provide solutions to the missing elements in BlazeDS. For example, paging (lazy loading) where you can initialize only the objects you need is in LiveCycle DS but not in BlazeDS. DigitalPrimates has developed dpHibernate which creates proxies for your real objects. When you touch the object, it will only then actually load in the real object. When dealing with a large collection of objects, lazy loading can be extremely helpful.
The Enterprise Service Bus pattern should also peak your interest. Frankly, Adobe probably would get better interest if they named these products ESB instead of DS. There are several definitions for ESB, and it is a bit of a buzzword these days. I gave a very simply definition for this, but, I hope you can see that you could decouple the service calls and thereby make your infrastructure more flexible to changes.