Messaging destinations is the central concept in publish/subscribe messaging supported by WebORB. The feature is available for Flex, AIR, Javascript, native Java/Android, and .NET clients. A program can be in the role of producer or consumer (or both). Producers publish messages into a destination and consumers subscribe to receive published messages. Typically messaging destinations are registered in a configuration file (WEB-INF/flex/messaging-config.xml), however, WebORB also supports destinations created at run-time – thus called dynamic messaging destinations. The dynamic nature of the destinations can add a lot of flexibility to applications relying on publish/subscribe messaging. For instance, one can easily create a short-lived messaging destination for quick message exchange or some private messaging. The example below demonstrates Java code registering a dynamic destination using the WebORB for Java API:
package demo.messaging.destination;
import weborb.ORBConstants;
import weborb.config.FlexMessagingServiceConfig;
import weborb.config.ORBConfig;
import weborb.config.ORBServerConfig;
import weborb.management.messaging.FlexMessagingDestination;
import weborb.messaging.v3.MessagingDestination;
import weborb.messaging.v3.MessagingServiceHandler;
import weborb.v3types.core.DataServices;
import java.util.Hashtable;
public class DestinationFactory
{
public String createMessagingDestination( String name ) throws Exception
{
// create destination object. This is as basic as it gets, constructor with the destination name
MessagingDestination destination = new MessagingDestination( name );
// setup the most basic properties - the name of the class handling
// subscriptions and publications and a class where the messages are stored
// until they are retrieved by the consumers.
Hashtable properties = new Hashtable();
properties.put( ORBConstants.MESSAGE_STORAGE_POLICY, "weborb.messaging.v3.MemoryStoragePolicy" );
properties.put( ORBConstants.MESSAGE_SERVICE_HANDLER, "weborb.messaging.v3.MessagingServiceHandler" );
// register properties
destination.setProperties( properties );
// initialize handler from the properties
destination.setConfigServiceHandler();
// register the destination
DataServices dataServices = ORBConfig.getORBConfig().getDataServices();
dataServices.getDestinationManager().addDestination( name, destination );
// REGISTERING DESTINATION SO IT IS VISIBLE IN THE MANAGEMENT CONSOLE
// The following two lines are needed if you would like the destination
// to appear in the management console, therefore the code below is optional
// set the channel name, so the console knows how to connect to the destination
// in the "Test Drive" mode.
destination.setChannelName( "my-polling-amf" );
FlexMessagingServiceConfig serviceConfig = ORBServerConfig.getFlexMessagingServiceConfig();
serviceConfig.addFlexMessagingDestination( FlexMessagingDestination.getDestinationScope( destination ) );
return name;
}
}
To further demonstrate how dynamic destinations can be used with the Flex client, see the following Flex application code. The application’s workflow consists of the following steps:
- User enters a name for a dynamic destination to create and pressed the Create Destination button.
- Flex client invokes the createMessagingDestination Java method shown above.
- When the remote method invocation returns a result, the Flex client constructs a Producer and a Consumer objects. The consumer is subscribed to the newly created destination.
- When the user enters text and clicks the Send Message button, the Flex client uses the Producer object to publish the message into the destination.
- The consumer object receives the message from the destination and displays it in the text area.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="100%" height="100%" creationComplete="init()">
<s:layout>
<s:FormLayout/>
</s:layout>
<s:states>
<s:State name="InitialState"/>
<s:State name="DestinationCreated"/>
</s:states>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.messaging.ChannelSet;
import mx.messaging.Consumer;
import mx.messaging.Producer;
import mx.messaging.channels.AMFChannel;
import mx.messaging.events.MessageEvent;
import mx.messaging.messages.AsyncMessage;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.RemoteObject;
import weborb.messaging.WeborbMessagingChannel;
private var remoteService:RemoteObject;
private var consumer:Consumer;
private var producer:Producer;
public function init():void
{
remoteService = new RemoteObject( "GenericDestination" );
remoteService.source = "demo.messaging.destination.DestinationFactory";
remoteService.createMessagingDestination.addEventListener( ResultEvent.RESULT, destinationCreated );
remoteService.createMessagingDestination.addEventListener( FaultEvent.FAULT, gotError );
}
private function destinationCreated( evt:ResultEvent ):void
{
currentState = "DestinationCreated";
consumer = new Consumer();
consumer.destination = evt.result as String;
//var channel:AMFChannel = new AMFChannel( "custom-amf-channel", "weborb.wo" );
var channel:WeborbMessagingChannel = new WeborbMessagingChannel( "custom-rtmp-channel", "rtmp://localhost/root" );
var channelSet:ChannelSet = new ChannelSet();
channelSet.addChannel( channel );
consumer.channelSet = channelSet;
consumer.addEventListener( MessageEvent.MESSAGE, gotMessage );
consumer.subscribe();
producer = new Producer();
producer.destination = evt.result as String;
producer.channelSet = channelSet;
}
private function gotError( evt:FaultEvent ):void
{
Alert.show( "Server reported an error: " + evt.fault.faultDetail );
}
private function createDestination():void
{
remoteService.createMessagingDestination( destinationName.text );
}
private function sendMessage():void
{
var asyncMessage:AsyncMessage = new AsyncMessage( messageText.text );
producer.send( asyncMessage );
}
private function gotMessage( evt:MessageEvent ):void
{
log.text = evt.message.body.toString() + "\n" + log.text;
}
]]>
</fx:Script>
<s:HGroup width="100%" paddingBottom="2" paddingTop="2" verticalAlign="middle">
<s:Label width="150" text="Destination Name:"/>
<s:TextInput id="destinationName"/>
<s:Button label="Create Destination" click="createDestination()"/>
</s:HGroup>
<s:HGroup width="100%" paddingBottom="2" paddingTop="2" verticalAlign="middle">
<s:Label width="150" text="Message:"/>
<s:TextInput id="messageText"/>
<s:Button label="Send" click="sendMessage()" enabled="false"
enabled.DestinationCreated="true"/>
</s:HGroup>
<s:HGroup width="100%" height="200">
<s:TextArea id="log" width="413" height="100%"/>
</s:HGroup>
</s:Application>
Since the client code references the weborb.messaging.WeborbMessagingChannel class (needed only if the client-server publish/subscribe communication should be done via RTMP), the application must reference weborb.swc in the Flash Build Path of the project. The library is available at:
WebORB for Java – [WEBOBR INSTALL DIR]/webapp/weborbassets/wdm
WebORB for .NET – [WEBOBR INSTALL DIR]/weborbassets/wdm
Complete Flex project with the code shown above can be downloaded from:
http://examples.themidnightcoders.com/blog/dynamicdestinations/DynamicDestinationDemo.zip
Compiled Java code can be downloaded from (the file should be deployed into WEB-INF/lib):
http://examples.themidnightcoders.com/blog/dynamicdestinations/dynamicdestinations.jar
For more information about the Dynamic Destination API, see the corresponding section in the WebORB Documentation.
