In yesterday’s post I talked a little bit about some of the details on how I used messaging to connect a front end on demand request to a back end scheduled data processing mechanism. In this post we’re going to talk about how to send data from a web page to a running Flex application without using HTTP. It is really quite easy.
First up you need a message queue that supports Stomp. Stomp is a text-based message queue protocol that a good number of message queue applications support. I chose ActiveMQ, mostly because of authentication issues I was running into with RabbitMQ that I didn’t have time to solve. Stomp isn’t turned on automatically so you need to change some config settings. I have details at my first post on how to do that.
In my demo I wanted to have real time notifications of when a sale came in from a Magento application. So the first thing to do would be to create a queue endpoint in ActiveMQ that you can send the data to. That’s the easy part. Next I needed to create an observer that would be triggered when a sale is made. Magento uses an event based system and so hooking in to that was relatively easy. The observer looked like this:
use vo\SaleItem;
use vo\Sale;
use log\Logger;
class Zend_Dashboard_Model_Observer
{
public function logSale(Varien_Event_Observer $observer)
{
$session = Mage::getSingleton('checkout/session');
$orderId = $session->getLastOrderId();
$order = Mage::getModel('sales/order')->load($orderId);
$items = $order->getAllItems();
$sale = new Sale();
$sale->date = time();
$sale->total = $order->getTotalDue();
foreach ($items as $item) {
$sItem = new SaleItem();
$sItem->name = $item->getData('name');
$sItem->price = $item->getData('price');
$sItem->qty = $item->getData('qty_ordered');
$sale->items[] = $sItem;
}
$logger = new Logger();
$logger->registerSale($sale);
}
}
The Logger class that it calls is where the messaging occurs.
namespace log;
use vo\Sale;
class Logger
{
private static $queues = array();
/**
*
* Retrieves a queue object based on the name
* @param string $queue
* @return \Zend_Queue_Adapter_Activemq
* @throws Exception
*/
public function getQueue($queue)
{
if (!isset(self::$queues[$queue])) {
$config = new \Zend_Config_Ini(__DIR__ . '/../../etc/config.ini');
if (!isset($config->mq->$queue)) {
throw new Exception('Undefined queue configuration');
}
$stomp = new \Zend_Queue_Adapter_Activemq(array());
$stomp->setQueue(
new \Zend_Queue(
array(
'name'=> $config->mq->$queue->endpoint
)
)
);
self::$queues[$queue] = $stomp;
}
return self::$queues[$queue];
}
public function registerSale(Sale $sale)
{
$queue = $this->getQueue('sales');
$date = new \Zend_Date();
$date->setTimestamp($sale->date);
$output = sprintf(
"%s Total: \$%s Items: %d",
$date->toString(\Zend_Date::DATETIME_MEDIUM),
$sale->total,
count($sale->items)
);
// Send notification
$queue->send($output);
}
}
The workings of the logger and the configuration are described in yesterday’s post. For this notification all I needed was a simple text message stating that a purchase was made and how much. I want to figure out how to send an AMF serialized object to a Flash front end but I haven’t had time to do that yet. So a simple text message will do.
Once the message is in the queue we now need to retrieve it in our Flex application. I used AS3Stomp for the connection. What I did was create a VGroup which could pretty much be inserted on any visual component. In there I created a list element that would be populated with the individual messages that were received from the queue. The data provider for the list is a simple array of the individual messages which had been received.
<?xml version="1.0" encoding="utf-8"?> <s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" width="100%" height="100%" horizontalAlign="center" creationComplete="vgroup1_creationCompleteHandler(event)" xmlns:stomp="org.codehaus.stomp.*"> <fx:Script> <![CDATA[ import flashx.textLayout.elements.ListElement; import mx.events.FlexEvent; import org.codehaus.stomp.Stomp; import org.codehaus.stomp.event.MessageEvent; import valueObjects.Sale; protected function vgroup1_creationCompleteHandler( event : FlexEvent ) : void { stomp.connect(); stomp.subscribe("/queue/sales"); } protected function stomp_messageHandler( event : MessageEvent ) : void { var str : String = event.message.body.readUTFBytes(event.message.body.length); var data : Object = new Object; data.label = str; salesMessages.addItem(data); } ]]> </fx:Script> <fx:Declarations> <stomp:Stomp id="stomp" message="stomp_messageHandler(event)" /> <s:ArrayCollection id="salesMessages" /> </fx:Declarations> <s:Label text="Sales"/> <s:List id="saleList" width="100%" height="100%" color="#000000" dataProvider="{salesMessages}" fontSize="13"></s:List> </s:VGroup>
The stomp object was provided as a declaration with a method associated with it’s “message” event which is thrown every time a new message comes in. When a new message comes in the event is fired and the messageHandler() method is called where we read the message data into a string and attach it to an object with a label property. Then we add it to the data provider at which point the list will update itself with the new value.
Easy.
Comments
No comments yet...