This will be the first in a series of posts where I’ll cover how you can do publish\subscribe and other messaging methods with Flex and Rails using ActiveMQ, the Rails ActiveMessaging plugin, and the STOMP protocol to get them all communicating. In this post I will describe how to create a simple Flex consumer that receives messages from a Rails app that serves as the producer.
Before we get to that, let’s start with a brief description of the technologies involved. The following descriptions are from the technologies’ respective websites:
Apache ActiveMQ
Apache ActiveMQ is the most popular and powerful open source Message Broker.
Apache ActiveMQ is fast, supports many Cross Language Clients and Protocols and many advanced features while fully supporting JMS 1.1 and J2EE 1.4. Apache ActiveMQ is released under the Apache 2.0 License.
ActiveMessaging
ActiveMessaging is an attempt to bring the simplicity and elegance of rails development to the world of messaging. Messaging, (or event-driven architecture) is widely used for enterprise integration, with frameworks such as Java’s JMS, and products such as ActiveMQ, Tibco, IBM MQSeries, etc.
And, lastly the protocol that we’re going to use to tie everything together:
STOMP
The Stomp project is the Streaming Text Orientated Messaging Protocol site (or the Protocol Briefly Known as TTMP and Represented by the symbol :ttmp).
Stomp provides an interoperable wire format so that any of the available Stomp Clients can communicate with any Stomp Message Broker to provide easy and widespread messaging interop among languages, platforms and brokers.
Now that you know a little something about technologies that we will be using (I am assuming that you probably already know about Flex and Rails), let’s build something.
Prerequisites:
- Ruby 1.8.6
- Rails 1.2.3
- Java 1.5.0_07+
- MySQL (or any other database that works with Rails migrations)
Here are the source files if you would like to follow along.
Source Files:
Creating the Rails App
Let’s kick things off by creating the Rails producer app. It’s going to be a really small app called sales_report that is used to capture and distribute simple sales data.
1. Crack open the database of your choice and create a database called sales_report. For example,
$ CREATE DATABASE sales_report
2. Create the app
$ rails sales_report
$ cd sales_report
3. Generate your sale model
$ script/generate model sale
4. Open up the 001_create_sales.rb migration that you just created in db/migrate and add the following
def self.up
create_table :sales do |t|
t.column :customer, :string
t.column :product, :string
t.column :quantity, :integer
end
end
5. Open up config/database.yml and configure it for your database. For example,
development:
adapter: mysql
database: sales_report
username: root
password: your_password_here
socket: /tmp/mysql.sock
6. Run the migration rake task to create the sale table that you defined in migration file above.
$ rake db:migrate
7. Generate the sales controller.
$ script/generate controller sales index
8. For this application,we really just need to be able to produce new sales records, so Rails scaffolding will work just fine. Open up sales_controller.rb and make it look like this:
class SalesController < ApplicationController
scaffold :sale
end
9. That’s all for the basic Rails app. Now it’s time to start working with ActiveMessaging. So, let’s install the plugin and a couple of gems that it uses.
$ gem install daemons
$ gem install stomp
$ script/plugin install http://activemessaging.googlecode.com/svn/trunk/plugins/activemessaging
10. Now that we have everything installed, let’s create an ActiveMessaging processor. We don’t actually need the processor for this tutorial, but it generates some other files that we do need.
$ script/generate processor sale
create app/processors
create app/processors/sale_processor.rb
create test/functional/sale_processor_test.rb
create config/messaging.rb
create config/broker.yml
create app/processors/application.rb
create script/poller
11. Open up config/broker.yml and configure the stomp adapter as follows:
development:
adapter:
stomplogin: ""
passcode: ""
host: localhost
port: 61613
reliable: false
12. Now open up config/messaging.rb and specify the destination for the queue, like so
ActiveMessaging::Gateway.define do |s|
s.destination :sale_queue, '/queue/Sale'
end
13. Almost done. The last step for the Rails app is to create an Observer that watches the Sale model to see when a new sale is saved to the database and then publishes it to the queue that you just set up.
$ script/generate observer sale
14. Now edit app/model/sale_observer.rb as follows.
require 'activemessaging/processor'
class SaleObserver < ActiveRecord::Observer
include ActiveMessaging::MessageSender
publishes_to :sale_queue
def after_save(sale)
record = sale.to_xml
publish :sale_queue, record
end
end
This class watches the Sale model. When a new sale record is saved to the database the after_save method is called. This method takes the new sale ActiveRecord instance converts it to XML and publishes it to the sale_queue.
15. Finally, boot up the server.
$ script/server
Installing ActiveMQ
Installing and running ActiveMQ is dead simple.
1. Just go and grab one of the latest snapshots from here.
2. Download it and unzip it.
3. Navigate to activemq/bin and run activemq.
4. If you need additional instruction, check out this page.
5. Once you have ActiveMQ up and running, proceed to the next section on building the Flex app.
The Flex App and the STOMP AS3 Client
To get Flex talking with ActiveMQ we are going to be using the STOMP protocol. When I first started looking into ActiveMQ I came across this ActionScript 3 STOMP client developed by Richard Jewson. I’ve since update the library substantially so that it implements the majority of the STOMP protocol. For now, you can get the source for the STOMP library by downloading the source for the Flex app. I am going to submitting this code to the STOMP project on codehaus.org, so in the future you will be able to grab updates from there.
For the Flex app we’ll just focus on the code that is needed to connect to ActiveMQ via STOMP and consume the xml that Rails is publishing. To makes things a bit easier, we’ll start with the completed Flex and just walkthrough the code. If you haven’t already download the source for the Flex app. To see what the Flex app looks like click here. As you can see it’s pretty much just a data grid that is used for displaying the sale info.
So, here is the important code, which is all inside the script tags in the Flex app:
[Bindable]
private var sales : ArrayCollection = new ArrayCollection();
private var stomp : STOMPClient = new STOMPClient();
private var queue : String = "/queue/Sale";
private function init () : void
{
stomp.connect("localhost", 61613);
stomp.subscribe( queue );
stomp.addEventListener(MessageEvent.MESSAGE, handleMessages);
stomp.addEventListener(ReceiptEvent.RECIEPT, handleReceipts);
stomp.addEventListener(STOMPErrorEvent.ERROR, handleErrors);
}
private function handleMessages(event : MessageEvent) : void
{
var incomingMsg : XML = XML(event.message.body);
var processedSale : ObjectProxy = simplerXMLDecoder(incomingMsg);
orders.addItem(processedSale);
}
private function handleReceipts (event : ReceiptEvent) : void
{
trace ("Got receipt: " + event.receiptID)
}
private function handleErrors (event : STOMPErrorEvent) : void
{
trace ("Error: " + event.error.body)
}
private function simplerXMLDecoder (x : XML) : ObjectProxy
{
var xdoc : XMLDocument = new XMLDocument();
xdoc.ignoreWhite = true;
xdoc.parseXML(x.toXMLString());
var decoder : SimpleXMLDecoder = new SimpleXMLDecoder(true);
return decoder.decodeXML(XMLNode(xdoc.firstChild)) as ObjectProxy;
}
Here’s what’s going on in this code.
- Up near the top we create a new STOMPClient
- Directly below we specify the destination for the queue that we will be subscribing to, which is the same destination that we specified in messaging.rb above.
- In the init() method, which is called when the application loads, we connect to the STOMP broker (ActiveMQ) and then subscribe to the queue.
- We then set up listeners to listen for messages from ActiveMQ.
All of the real action is happening in the handleMessages method.
- The handleMessages method gets called when the Rails app sends out the xml for a new sale.
- When a new message is received we take the body of the message (which is the xml from Rails) and use the XMLDecoder class to turn it into a bindable ObjectProxy.
- Finally, the new sale is added to the sales ArrayCollection, which is the data provider for the data grid in the Flex app.
Getting Everything Up and Running
Alright, now we are actually ready to run something. Assuming that the Rails app and ActiveMQ are still running, all that we need to do is launch the Flex app. You can either build the app yourself from the source files, or you can go in to the source files, open the bin folder and launch StompSalesReport.html.
Now, open a browser and navigate to http://localhost:3000/sales/new
You should see our spartan, but functional, scaffolded interface. Enter some product info and click Create.

Now if you switch back to Flex app, you should see the following:

Pretty exciting stuff. Immediately after the sale was saved to the database, the SaleObserver published it to the queue, where ActiveMQ pushed it out to the Flex app.
One last little tidbit. If you change the code in init() method in the Flex app so that it looks like this:
private function init () : void
{
var ch : ConnectHeaders = new ConnectHeaders();
ch.clientID = "MYTOTALLYUNIQUECLIENTID";
stomp.connect("localhost", 61613, ch);
var sh : SubscribeHeaders = new SubscribeHeaders();
sh.amqSubscriptionName = "MYSUBSCRIPTION";
stomp.subscribe( queue, sh );
stomp.addEventListener(MessageEvent.MESSAGE, handleMessages);
stomp.addEventListener(ReceiptEvent.RECIEPT, handleReceipts);
stomp.addEventListener(STOMPErrorEvent.ERROR, handleErrors);
}
By passing a client-id header on connect and a subscriptionName header on subscribe we create what is known as a durable subscriber.
If you compile the Flex app, launch it and then close it. Then go in back to the Rails app and create a new sale, relaunch the Flex app and you should immediately see the sale show up.
Whew! That’s it. This post was way too long. I am thinking that it may be easier to cover this stuff in a screencast. Let me know in the comments if you think a screencast would be a good idea.
As always, let me know if you have any questions.