Externalizing Service Configuration using BlazeDS and LCDS

Externalizing Service Configuration using BlazeDS and LCDS

A typical source of confusion when developers start working with RemoteObject or other BlazeDS/LCDS related classes is where and most importantly *when* the configuration of your services is being read.

The question often arises after an application stops working when you move it to another server. This is one of the most frequently asked questions related to BlazeDS and LCDS, so I figured I would answer it here. There is nothing really new in this post, but hopefully this will be a good point of reference.

When you create a new BlazeDS or LCDS project in Flex Builder, you are typically told to select J2EE as the “Application Server Type” and then check “use remote object access service”. This adds a compiler argument pointing to the location of your services-config.xml. If you check the Flex Compiler properties of your Flex Builder project, you’ll see something like this:

-services “c:\blazeds\tomcat\webapps\samples\WEB-INF\flex\services-config.xml”

When you then compile your application, the required values of services-config.xml are baked into the SWF. In other words, services-config.xml is read at compile time and not at runtime as you may have thought intuitively. To abstract things a little bit, you can use tokens such as {server.name}, {server.port}, and {context.root} in services-config.xml. However, {context.root} is still substituted at compile time, while {server.name} and {server.port} are replaced at runtime using the server name and port number of the server the SWF was loaded from (which is why you can’t use these tokens for AIR applications).

Fortunately, the Flex SDK provides an API that allows you to configure your channels at runtime and entirely externalize your services configuration from your code (you definitely don’t want to recompile your application when you move it to another server). At a high level, it works like this:

var channelSet:ChannelSet = new ChannelSet();
var channel:AMFChannel = new AMFChannel("my-amf", "http://localhost:8400/lcds-samples/messagebroker/amf");
channelSet.addChannel(channel);
remoteObject.channelSet = channelSet;

This is still not what we want because the endpoint URL is still hardcoded in the application. At least in this case it’s obvious that it is. So, the last step is to pass that endpoint URL value at runtime. There are a number of ways you can pass values to a SWF at runtime (flashvars, page parameters, etc). The approach I usually use is to read a configuration file using HTTPService at application startup. That configuration file includes (among other things) the information I need to programmatically create my channel set at runtime. Here is a basic implementation:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	applicationComplete="configSrv.send()">

	<mx:Script>
	<![CDATA[

	import mx.controls.Alert;
	import mx.messaging.channels.AMFChannel;
	import mx.messaging.ChannelSet;
	import mx.rpc.events.ResultEvent;

	private var channelSet:ChannelSet;

	private function configResultHandler(event:ResultEvent):void
	{
		var xml:XML = event.result as XML;
		var amfEndpoint:String = "" + xml..channel.(@id=="amf").@endpoint;
		if (amfEndpoint == "")
		{
			Alert.show("amf channel not configured", "Error");
		}
		else
		{
			channelSet = new ChannelSet();
			var channel:AMFChannel = new AMFChannel("my-amf", amfEndpoint);
			channelSet.addChannel(channel);
			ro.channelSet = channelSet;
			ro.getProducts();
		}
	}

	]]>
	</mx:Script>

	<mx:HTTPService id="configSrv" url="config.xml" resultFormat="e4x" result="configResultHandler(event)"/>

	<mx:RemoteObject id="ro" destination="product"/>

	<mx:DataGrid dataProvider="{ro.getProducts.lastResult}" width="100%" height="100%"/>

</mx:Application>

The configuration file looks like this:

<?xml version="1.0" encoding="utf-8"?>
<config>
	<channels>
		<channel id="amf" endpoint="http://localhost:8400/lcds-samples/messagebroker/amf"/>
	</channels>
</config>

NOTE: With that type of runtime configuration in place, you can create plain Flex Builder projects (you can select None as the application server type).

This particular example is not extremely flexible. It assumes I will always work with an AMF channel and therefore the only thing my application needs to know at runtime is the AMF channel endpoint URL. For RemoteObject that’s a fairly safe bet, however for messaging-related classes (Producer and Consumer), you may also want to externalize the type of channel you use (AMF Polling, long polling, streaming, RTMP, etc.). Before you start creating that kind of dynamic configuration system, you may want to take a look at the Flex ActionScript framework that does that very well.

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • LinkedIn
  • StumbleUpon
  • Twitter
This entry was posted in Air, BlazeDS, Flex, LCDS. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

26 Comments

  1. stef
    Posted March 23, 2009 at 1:38 pm | Permalink

    thank you christophe – very helpful! SB

  2. Astor Digital
    Posted March 24, 2009 at 1:05 pm | Permalink

    We actually had the requirement to read these parameters(ie http://uniqueserver:8080) via flash vars, then construct the secure amf channel.

  3. Posted March 24, 2009 at 5:09 pm | Permalink

    Just to note that the Swiz framework includes very nice support for dynamic ChannelSet creation.

  4. Posted March 24, 2009 at 8:46 pm | Permalink

    Hi Brian,
    I looked at Swiz and I like it as I hope you can tell from the blog post. You guys are doing a really great job. On this particular topic of externalizing service configuration, I didn’t see a built-in solution to externalize the configuration from the source code (I may have missed it as I only had a limited amount of time to explore the framework). In this example, the port and context root are still hard coded.
    Also, at first glance, I didn’t see the real benefit of using DynamicChannelSet compared to the standard ChannelSet class. For example, in my Beans.xml I can replace:

    <DynamicChannelSet id="myAmfChannel">
    <serverPort>8400</serverPort>
    <contextRoot>/lcds-samples</contextRoot>
    </DynamicChannelSet>

    <mx:RemoteObject id="contactService" destination="contacts" channelSet="{myAmfChannel}"

    with

    <mx:ChannelSet id="channelSet">
    <mx:AMFChannel id="amf" url="http://localhost:8400/lcds-samples/messagebroker/amf"/>
    </mx:ChannelSet>

    <mx:RemoteObject id="contactService" destination="contacts" channelSet="{channelSet}"/>

    The second approach uses the SDK classes and doesn’t have a dependency on services-config.xml either. Are there additional benefits in using DynamicChannelSet?
    Thanks,
    Christophe

  5. aivilo
    Posted March 26, 2009 at 12:49 am | Permalink

    Hi Christophe
    We are developing a flex chart componment like Yahoo finance. but when we connected it with live datafeed, we experience serious lagging probelm. It got worse when we add technical indicators to it. We have asked for suggestions from Adobe HK. They recommend us to reduce the frequency of datafeed var numNull:int = Math.floor( (1000/9) /(1000/24)) / 2; to avoid accumulation of refresh events. But performance is prime to us and we need to use realtime data. Could you give us some suggestions on how to handle this problem. We are so impressed with your traderdesktop. It would be grateful if you could you give us an email so that we could show you our development? Thanks.

  6. Posted March 27, 2009 at 6:04 pm | Permalink

    Christophe,

    I always enjoy reading your posts. I recently had that same problem since I was trying to install BlazeDS on a remote server and every single tutorial on the internet I found was about installing it and running it locally. I made a post that had to do with that on my blog althought you explained it a lot better than I did. Check it out if you’d like: BlazeDS & WSDL Introspection.

  7. Vineet Bhatia
    Posted April 3, 2009 at 9:11 am | Permalink

    Hi Christophe,

    If we remove services-config.xml from compiler arguments we get “MessagingError message=’Destination ‘Destination_name’ either does not exist or the destination has no channels defined (and the application does not define any default channels.”

  8. How to NOT ignore java beans read only properties in Java?
    Posted May 13, 2009 at 2:18 am | Permalink

    As stated in LCDS AMF serialization documentation, the read-only properties of a java bean are ignored in the AMF serialization process. What do I need to do so that the read only properties are also serialized?

    Any link or documentation would be helpful

  9. schujfi
    Posted May 17, 2009 at 9:45 am | Permalink

    If you externalize your services, don’t forget to make the Server available to the clients placing the crossdomain.xml file in the root server.

  10. Paulo Fabiano Langer
    Posted June 29, 2009 at 3:49 pm | Permalink

    Hi Christophe, nice post :)
    Could you give me some tips about my issues?
    I have a main java web application that needs to send messages (jms) to my flex dashboard application. Both applications are in the same server but my blazeDS is running in other server under tomcat.
    How could I config both applications to produce and consume messages using the remote blazeDS ?
    Some people told me to use JNDI but I don´t know how very well that API.
    Thanks

  11. Posted July 28, 2009 at 4:12 am | Permalink

    thank you admin good fluser

  12. Posted July 29, 2009 at 1:39 pm | Permalink

    I cannot believe this will work!

  13. Brian Bonner
    Posted August 19, 2009 at 11:40 pm | Permalink

    I would like have a linux server running as our continuous integration.

    We build locally using Flexbuilder on windows, but we cant get linux to compile any services. Any ideas???

  14. Bharat
    Posted August 26, 2009 at 9:21 am | Permalink

    Hi Christophe,

    I am developing an application using LCDS and J2EE.
    What are the steps required to build an application.
    What all do we need?

  15. Raghu
    Posted November 4, 2009 at 9:07 pm | Permalink

    Hi Christophe,

    I have developed an application using Flex , LCDS and J2EE. The application works very well when deployed in my local system. When I deploy the application in another system, i see that the LCDS call are not happening. What might the resolution for this issue?

    Thank You

  16. Nikos Katsikanis
    Posted November 13, 2009 at 3:23 pm | Permalink

    Awesome code Sir, I guess I can delete the following code from my service-config.xml

    <endpoint uri="//secret

    since I define the stuff in my extra service file on my server?

    thanks for any tips

  17. Posted November 21, 2009 at 12:08 pm | Permalink

    program yükle Good admin than you

  18. Posted February 2, 2010 at 4:59 pm | Permalink

    Use it with a lot of caution!!!!

    It seems to work, but the code really doesn’t works when you open several channels at the same time. You will get a lot of “Channel disconnected” exceptions.

    I think the ideas exposed here are very very useful and very they are well explained. Thanks a lot. Though users could have problems if they use your code without any correction.

    Pablo.

  19. Posted February 2, 2010 at 8:05 pm | Permalink

    Hi again!

    Problem solved! Define and initialize an unique static ChannelSet and apply it to all created remote objects.

    I guess ChannelSet (or AMFChannel) is a limited System resource. So you can’t open a lot of channels simultaneously. But you can reuse the same channel for all remote objects.

    That is based on my experience. I can’t justify that.

    Thanks a lot Christopher!

  20. Posted February 25, 2010 at 4:50 am | Permalink

    Hi Cristophe,

    are you aware that you can use relative URL’s for the endpoints, too? The URL is resolved relative to the url where the Flex file was loaded from. This solves the “my flex file moved to another server” problem, without any extra complexity.

    Of course, this only works if the file is access from the server.

    Regards,

    Allard

  21. Santhi
    Posted April 26, 2010 at 8:38 pm | Permalink

    I am trying Flex client configuration for BlazeDS in SunOneWebserver.
    I am getting error like this:
    faultcode=”Client.Error.MessageSend”
    faultDetail=”Channel.Connect.Failed error NetConnection.Call.Failed.

  22. Priyabrat Mohapatra
    Posted July 25, 2010 at 6:42 am | Permalink

    Hi Vineet,

    I could compile and execute this sample code without specifying -service option to mxmlc (sdk version 3.5).

    But yes, BlaseDS throws runtime exceptions while initializing MessageBrokerServlet if I start it

    without services-config.xml in WEB-INF/flex
    Exception: flex.messaging.config.ConfigurationException: Please specify a valid ‘services.configuration.file’ in web.xml.
    You specified ‘/WEB-INF/flex/services-config.xml’. This is not a valid file system path reachable
    via the app server and is also not a path to a resource in your J2EE application archive.
    or
    removing the element from services-config.xml [as suggested by Nikos Katsikanis"]
    Exception: flex.messaging.config.ConfigurationException: Attribute ‘endpoint’ must be specified for element ‘channel-definition’.

    or
    not having a channel-definition in services-config.xml that is referred by any element in remoting-config.xml.
    Exception: flex.messaging.config.ConfigurationException: channel not found for reference ‘my-amf’.

    I could simulate the kind of client side error what you get i.e.
    [RPC Fault faultString="[MessagingError message='Destination 'echoServiceDestination' either does not exist or the destination has no channels defined (and the application does not define any default channels.)']” faultCode=”InvokeFailed” faultDetail=”Couldn’t establish a connection to ‘echoServiceDestination’”]
    by removing applicationComplete=”configSrv.send()” from the main application tag.

    But the NetConnection client side error i.e.
    [RPC Fault faultString="Send failed" faultCode="Client.Error.MessageSend" faultDetail="Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Status 500: url: 'http://localhost:8090/blazeds/messagebroker/amf'"]
    occurs in all other cases viz when there is run time exception when initializing MessageBrokerServlet or wrong endpointurl (say port as 8090 instead of 8080) specified in config.xml as might be the case with Shanthi.

  23. Posted July 31, 2010 at 6:45 am | Permalink

    Bedava herşey burada

  24. Posted August 1, 2010 at 10:20 am | Permalink

    Kral oyunun en mükkemmel sitesi

  25. Jateen
    Posted August 23, 2010 at 4:24 am | Permalink

    I am getting total time in MessagePefirmanceUtils as
    -ve. Is there any compatability issues of lcds with Java 1.6

  26. Posted August 26, 2010 at 5:34 am | Permalink

    Thanks for the valuable information. Recently i tried switching my applications to a different server and found the BlazeDs annoying. Now i am running in my new server. Thanks for the solution.

    Thanks
    Collin paul
    Learn Forex

6 Trackbacks

  1. [...] Externalizing Service Configuration using BlazeDS… (from Christophe Coenraets) [...]

  2. [...] had recently read Christophe Coenraets blog post title, “Externalizing Service Configuration using BlazeDS and LCDS” which addresses the same issue with configuring Flex applications to use BlazeDS or [...]

  3. By One more thing… « M@ Blog on April 19, 2009 at 6:56 pm

    [...] documentation to figure something out but Christophe Coenraets came to the rescue with a post on externalizing your service configuration that has it covered. Posted in BlazeDS, Flex. Tags: BlazeDS, Flex, LCDS. No Comments [...]

  4. [...] Note: In a real life application, you would not want to hardcode the endpoints of your services in your source code. You could use the XML configuration option to configure your endpoints in a more “externalized” fashion. More on this topic here. [...]

  5. [...] À consulter sans attendre : l’article. [...]

  6. By Constantiner's blog on January 19, 2010 at 7:47 pm

    Dynamically loaded BlazeDS configuration in Flex applications…

    For people who wants to use server configuration (I mean channels, endpoints and remoting destinations from BlazeDs/LCDS services-config.xml and remoting-config.xml) loaded in runtime instead of common practice with reading configs in compile time Cris…

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>