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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 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...