Not yet rated
Tags:



Problem

Flex SDK provides an API for publish/subscribe operations through the Consumer/Producer classes. At the same time MSMQ is a robust messaging system enabling publish/subscribe message exchange paradigms for Windows/.NET environments. Integration between Flex pub/sub and MSMQ is powerful combination, but it is not clear how the two can integrate.

Solution

The solution is to use a .NET infrastructure environment which can understand the messages sent by Flex Producer/Consumer APIs and enable message exchange through MSMQ. WebORB for .NET enables such integration. The recipe review the code and the configuration required for the integration.

Detailed explanation

Overview

The recipe reviews a scenario where messages are published by a native Windows (.NET) application into MSMQ. Once a message is published, it is immediately delivered to all Flex consumers connected to the queue. The diagram below demonstrates data flow in the example. The 'Message Queue Publisher'  is a native Windows application with access to a MSMQ queue. It publishes a message (.NET complex type) into a queue. WebORB subscribes to the same queue on behalf of the connected Flex clients. As soon as a message is placed in the queue, WebORB delivers it to all Flex clients as an ActionScript object:

Requirements

  • WebORB for .NET v.3.6.0.3 or later
  • Microsoft .NET Framework 2.0 or later
  • Flash Builder 4 or Flex SDK v 3.5 or later
  • Microsoft Message Queue (MSMQ)

Resources

 

Data Producer - Windows Publisher

Message publisher is a Windows Forms application. It creates a timer controlled by the Start and Stop buttons.

When the timer is running, it publishes a message into a queue on each timer interval. Each message is a serializable object (instance of the Car class):

 

        private void publishTimer_Tick( object sender, EventArgs e
)
{
     // create a new object instance
     Car car = new Car();

     // populate instance properties
     car.Make = "TurboQ-" + messageCounter;
     car.Model = "MSMQ-2007-" + messageCounter;
     car.Mileage = messageCounter;
     messageCounter++;

     // display the number of published message in the label
     counterLabel.Text = messageCounter.ToString();

     //publish message into the queue
     myMessageQueue.Send( car );
}
  
The message queue is identified by the myMessageQueue object. It is configured as a control added to the application from the Visual Studio Toolbox:

 
myMessageQueue object has the following properties:

 
Objects published into the queue are instances of the Car class:
                namespace ORBExamples
{
    [Serializable()]
    public class Car
    {
        private string make;
        private string model;
        private long mileage;

        public string Make
        {
            get { return make; }
            set { make = value; }
        }

        public string Model
        {
            get { return model; }
            set { model = value; }
        }

        public long Mileage
        {
            get { return mileage; }
            set { mileage = value; }
        }
    }
}
    
Notice the class has the Serializable attribute. The attribute is required since the MSMQ queue is configured to use binary message formatter. Additionally, it is important to compile the Car class in a separate class library and reference the project from Windows Publisher. The reason for such configuration is the class must be shared between the Publisher and the WebORB processes. When WebORB picks up a message from the queue, the object in the message is automatically deserialized. As a result, object's class in the message must be present in the WebORB memory space. Full source code listing and project file for the queue publisher application are available in the Resources section of this article.

WebORB Configuration

WebORB functions as a gateway between MSMQ queues and Flex clients. Flex client can use the mx.messaging.Consumer or weborb.messaging.WeborbConsumer API to receive messages from a queue. When a message is published in a queue, WebORB receives it and routes to the client. WebORB exposes MSMQ queues as messaging destinations. A queue must be configured as a destination in messaging-config.xml located in the [WEBORB-INSTALL]/WEB-INF/flex directory. The queue used by the Windows Publisher application shown above is .\private$\weborb-mqpush. To configure the queue as a Flex messaging destination, the following XML must be added to messaging-config.xml:
                                <destination id="mqtoflex">
  <properties>
    <msmq>
      
<path>.\private$\weborb-mqpush</path>
      <!-- zero means 'do not send past messages'. 
           Set to -1 to receive previously sent messages -->
      <deliverPastMessages>0</deliverPastMessages>
      <BasePriority>0</BasePriority>
     
<Category>00000000-0000-0000-0000-000000000000</Category>
      <Label>WebORB MessageQueue for Messages from Windows
client</Label>
      <MaximumQueueSize>4294967295</MaximumQueueSize>
      <UseJournalQueue>false</UseJournalQueue>
     
<MaximumJournalSize>4294967295</MaximumJournalSize> 
    </msmq>
  </properties>
  <channels>
    <channel ref="weborb-rtmp"/>
  </channels>
</destination>
        
The configuration node above registers the <code>mqtoflex</code> messaging destination. The destination is mapped to the same MSMQ queue used by the Windows Publisher. The <code><msmq></code> node contains additional properties configuring the queue. You can see their description in messaging-config.xml included with the WebORB distribution.

Developing Flex Client

Flex client can use either the mx.messaging.Consumer or weborb.messaging.WeborbConsumer API to subscribe to the messaging destination.
 
When a message is available in the destination, WebORB delivers it to the subscribers. In this example, the destination is linked with MSMQ, as a result, the source of messages is a message queue. WebORB will deliver all message published in the queue to Flex consumers.
 
Creating a Flex consumer requires very little code. You need to know the name of the messaging destination and must specify a function to be called when a message arrives. The function is added as a listener for the MessageEvent.MESSAGE event:
                                               
            
                                                import
weborb.messaging.WeborbConsumer;
import mx.messaging.events.MessageEvent; 
[Bindable]
private var car:Car;
private var consumer:WeborbConsumer;

public function doConnect():void
{
  consumer = new WeborbConsumer();
  consumer.destination = "mqtoflex";
  consumer.addEventListener( MessageEvent.MESSAGE, receivedMessage
);
  consumer.subscribe();
}
            
Processing received messages takes place in the receivedMessage function:
                                                        public
function receivedMessage( event:MessageEvent ):void
{
  // store the value in a local 'bindable' variable
  // UI will display properties through the data binding
  car = Car( event.message.body );
}
              
Arrived messages contain instances of the ActionScript Car class. It is important to instruct the client runtime to map server-side objects to the corresponding client-side type. The function call shown below accomplishes that:
                                                                //
init is called through the creationComplete event
public function init():void
{
  // map server-side to the client-side type
  // ORBExamples.Car is a full type name of the class
  // of the objects sent by the server
  // Car is a client-side class the remote objects
  // should be mapped to
  flash.net.registerClassAlias( "ORBExamples.Car", Car );
}
                
The Car class used in the client program has the same structure and field names as the remote .NET counterpart:
                                                                
package
{ 
  [Bindable]
  public class Car
  {
    public var Make:String;
    public var Model:String;
    public var Mileage:Number;
  }
}
                
Full source code listing and a Flex Builder project are available in the Resources section of the article.

Running the Example

Follow the steps below to run the example:
  1. Download publisher and 'shared classes' projects, compile and run Windows Publisher.
  2. Download and install WebORB. Make sure WebORB messaging destination is added to messaging-config.xml. 
  3. Make sure to add "-services WEB-INF/flex/weborb-services-config.xml" to the "Additional compiler arguments" in Flex Compiler section of your Flash Builder project. 
  4. Deploy shared classes assembly into weborb, by copying the DLL into the /bin folder under WebORB installation root directory.
  5. Open a command prompt window and change the directory to the WebORB product installation (/Inetpub/wwwroot/weborb30)
  6. Run weborbee.exe. This is the standalone mode of the WebORB Messaging Server. It runs as an independent process and does not require IIS.
  7. Download flex project, compile and run Flex client.
  8. Click 'Connect' in the Flex client interface. You should see some activity in the weborbee process.
  9. Click 'Start' in the Windows Publisher window. Messages will be published to MSMQ and delivered to Flex.
Things to try:
  1. Add additional Flex clients, connect and see messages delivered to all Flex clients;
  2. Try stopping and starting Windows Publisher;
  3. Open Control Panel > Administrative Tools > Computer Management > Services and Applications > Message Queing > Private Queues. Locate the weborb-mppush queue and check the queue messages.

 

Conditional Message Delivery

In the example above WebORB unconditionally  delivers all MSMQ messages to every Flex client. It is also possible to add conditional logic in the message delivery chain. This can be done with message selectors. A selector is a special server-side class associated with a messaging destination. If a selector is configured, WebORB passes every message received from the queue to the selector object. The selector can either transform the message or instruct WebORB to cancel message delivery to a consumer. A selector class must implement the following interface:
                                                                   
            using System;
using System.Collections.Generic;
using System.Text;

using Weborb.V3Types;
namespace Weborb.Messaging.V3
{
  public interface IMessageSelector
  {
    /**
     * Passes the selector value from consumer.
     * Consumer instances can assign a value to the 
     * 'selector' property of the Consumer class
     */ 
    void setClientSelectorValue( String selectorValue );

    /**
     * Process a message originally sent by a Flex publisher.
     * Return null to cancel message delivery.
     */ 
    Object processClientMessage( V3Message message );

    /**
     * Process a message sent from a non-Flex client.
     * Return null to cancel message delivery.
     */ 
    Object processServerMessage( Object message );

    /**
     * Set the id of a client associated with this selector
     */ 
    void setClientID( String clientID );
  }
}
                  
Below is a sample implementation which can be used with the example from this article. Selector is invoked every time before a message is sent to a client. The selector can either change the message to be sent to the client or return null to cancel message delivery.
                                                                   
                    using System;
using Weborb.Messaging.V3;
using Weborb.V3Types;

namespace ORBExamples.Messaging
{
    public class CustomSelector : IMessageSelector
    {
        private string clientID;


        public void setClientSelectorValue( String selectorValue )
         {
         }

        public object processClientMessage( V3Message message )
        {
            // no filtering for messages published from Flex
clients
            return message;
        }

        public object processServerMessage( object message )
        {
            Car carObj = (Car) message;
           
            // rollback a few miles. 
            // don't tell anyone we did it:
            carObj.Mileage /= 2;
            return carObj;
        }

        public void setClientID( string clientID )
        {
            this.clientID = clientID;
        }
    }
}
                      
To configure a selector class, enter its full type name in the node of your destination configuration in WEB-INF/flex/messaging-config.xml. For example, to register the selector shown above, use the following configuration:
                                                                   
                            <destination id="mqtoflex">
  <properties>
    
<selector>ORBExamples.Messaging.CustomSelector</selector>
    <msmq>
      <path>.\private$\weborb-mqpush</path>
      <!-- zero means 'do not send past messages'. 
           Set to -1 to receive previously sent messages -->
      <deliverPastMessages>0</deliverPastMessages>
      <BasePriority>0</BasePriority>
     
<Category>00000000-0000-0000-0000-000000000000</Category>
      <Label>WebORB MessageQueue for Messages from Windows
client</Label>
      <MaximumQueueSize>4294967295</MaximumQueueSize>
      <UseJournalQueue>false</UseJournalQueue>
     
<MaximumJournalSize>4294967295</MaximumJournalSize> 
    </msmq>
  </properties>
  <channels>
    <channel ref="weborb-rtmp"/>
  </channels>
</destination>
                        
 It is also possible to identify a client with an ID. The subscribe() method can optionally accept client ID as a string value. WebORB passes client ID to the message selector using the setClientID() call. Additionally, if a consumer needs to pass a value into the selector in the runtime, it can use the selector property available in the consumer class. As soon as a value is assigned, the client sends it to the server and WebORB passes it to the destination's selector object.

+
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.

Report abuse

Related recipes