by Kevin Schroeder | 9:24 am

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...

Leave a Reply

Your email address will not be published. Required fields are marked *