March 16, 2010

BlazeDS: Creating endpoint at runtime

Why? Because I do not want to bother end users with xml configuration files. Simple as that.
Biggest enemy of your application is user itself. Therefore, reducing possibility to make a mistake is most important goal if you wish to left good impression with your app. This was one of steps that I take on the road to make Collyba installation procedure as easy as possible.
As I said in previous blog, while I was working on this, insight  to BlazeDS source files was of great help. Actually that is where I found a solution.

What are channels and endpoints?
Channels are client-side objects that encapsulate the connection behavior between Flex components and the BlazeDS server. Channels communicate with corresponding endpoints on the BlazeDS server. You configure the properties of a channel and its corresponding endpoint in the services-config.xml file.
But in our case, we won't configure it in XML file but programmatically.

/**
* Creates endpoint. Run this before creating destination.
* @id hint="Channel Id which communicate with corresponding endpoints on the BlazeDS server."
*/
public void function createEndpoint(required string channelId){
 //svn: http://opensource.adobe.com/svn/opensource/blazeds/trunk/modules/core/src/flex/messaging/MessageBroker.java
 var brokerClass = createObject('java','flex.messaging.MessageBroker');
 var broker = brokerClass.getMessageBroker( javacast('null','') );
 var channelSets = broker.getAllChannelSettings();
 var chennIds = broker.getChannelIds();
 
 //check if channel/endpoint is already created
 if (arrayContains(chennIds,arguments.channelId)){
  return;
 }
 
 /*Channel definiton properties*/
 //svn: http://opensource.adobe.com/svn/opensource/blazeds/trunk/modules/common/src/flex/messaging/config/ChannelSettings.java
 var channelSettings = createObject('java','flex.messaging.config.ChannelSettings').init(arguments.channelId);
 //svn: http://opensource.adobe.com/svn/opensource/blazeds/trunk/modules/common/src/flex/messaging/config/ConfigMap.java
 var channelProperties = createObject('java','flex.messaging.config.ConfigMap').init();
 var chPropSerialize = createObject('java','flex.messaging.config.ConfigMap').init();  
 var endpoint = '';
 
 channelSettings.setClientType("mx.messaging.channels.AMFChannel");
 channelSettings.setEndpointType("coldfusion.flash.messaging.CFAMFEndPoint");
 channelSettings.setUri("http://{server.name}:{server.port}{context.root}/flex2gateway/cfamflongpolling");

 channelProperties.addProperty("add-no-cache-headers","false"); 
 channelProperties.addProperty("polling-enabled","true");
 channelProperties.addProperty("polling-interval-seconds","0");
 channelProperties.addProperty("client-wait-interval-millis","1");
 channelProperties.addProperty("wait-interval-millis","60000");
 channelProperties.addProperty("max-waiting-poll-requests","200");

 chPropSerialize.addProperty("enable-small-messages","false");
 channelProperties.addProperty("serialization",chPropSerialize);  
 
 channelSettings.addProperties(channelProperties);
 
 /*Channel definiton endpoint*/
 //svn: http://opensource.adobe.com/svn/opensource/blazeds/trunk/modules/core/src/flex/messaging/endpoints/Endpoint.java
 //Creates an Endpoint instance, sets its id and url
 endpoint = broker.createEndpoint(
     arguments.channelId, 
     "http://{server.name}:{server.port}{context.root}/flex2gateway/cfamflongpolling",
     channelSettings.getEndpointType());
 // Initialize the endpoint with id and properties
 endpoint.initialize(arguments.channelId, channelSettings.getProperties());
 //Start the endpoint
 endpoint.start();
 
 channelSets[arguments.channelId] = channelSettings;
 broker.setChannelSettings(channelSets);
}

XML equivalent of  this channel/endpoint definition ( set in services-config.xml) is:
<channel-definition id="collyba-longpolling-amf" class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://{server.name}:{server.port}{context.root}/flex2gateway/cfamflongpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
 <enable-small-messages>false</enable-small-messages>
 <add-no-cache-headers>false</add-no-cache-headers>
 <polling-enabled>true</polling-enabled>
 <polling-interval-seconds>0</polling-interval-millis>
 <client-wait-interval-millis>1</client-wait-interval-millis>
 <wait-interval-millis>60000</wait-interval-millis>
 <max-waiting-poll-requests>200</max-waiting-poll-requests>
 <serialization>
  <enable-small-messages>false</enable-small-messages>
 </serialization>
</properties>
</channel-definition>

There are 2 crucial points here:
a) flex.messaging.config.ChannelSettings class holds all information from channel-definition definition element from services-config.xml file
b) createEndpoint method call. This is a place when we create Endpoint instance assign it to MessageBroker

Easy, isnt't it. Well it wasn't for me. But, knowing that I'll save you at least a day of R&D makes me happy :)

2 comments:

Raymond Camden said...

Thank you for sharing your last two blog entries. Any chance you can submit these to CFLIb?

Marko said...

Glad you like it Ray.
Sure I can and will. When it comes to endpoint creation, I think it should be re-factored a bit to make it more flexible. There are many different channel/endpoint configuration sets and this is example of just one.
Thinking of adding additional attribute which will be an XML with channel properties () that will be translated into ConfigMap structure.

However, If you think that is ok to submit it "as is", I'll do it and upgrade it later.

Destination method can be used "as is".