Flex remoting without configuring the client

Jettro Coenradie
For a while I am experimenting with flex. I wrote quite some posts about flex and security and I started writing about the Springframework BlazeDS Integration project. One thing that I do not really like about the configuration is the way to configure the remoting. All the hassle with the service-config.xml that needs to be available on the client as well as on the server. Not really nice. Using the maven way of creating a jar with these config files and unzipping this jar into the web server project as well as the client flex project is a way. Still, not ideal when developing in your ide when you want to add a new remote service.
What is the arternative? On the serverside, the mentioned spring project is doing a good job. You do not have to configure all endpoints. But you still need something on the client.
This post talks about a mechanism to enable you to loose all this configuration on the client

An overview

So what am I planning to do. Using the Properties object from the Spring-ActionScript project I will load a property file from the server. This property file will contain the parameters required by the remote objects to connect to an endpoint. The property files will not be on the server, the request will be captured by the Dispatcher servlet from spring. Special controller classes will create the properties requested by the client and a view class creates a stream to the client. That way the client does not know the requested file is actually a dynamic resource.
Does that sound complicated? Well, read on and I’ll explain it step by step.

The server side

As mentioned in the introduction, we use the special spring BlazeDS integration project on the server. I am not going to discuss the configuration anymore. Read my previous post Wow springframework enters the actionscript and flex domain to learn how to do that. For this post I’ll focus on the differences.
So what do we need? We need the server to respond to the url:
http://localhost:8080/books-web/config.properties
with the result:
host=localhost
port=8080
context-root=books-web
And of course the result should be different when running on another server.

web.xml

We add a servlet mapping for a *.properties

 Spring MVC Dispatcher Servlet
 *.properties

spring-web.xml

We need to add a url mapping, and we have to add a mapping for the config.properties request. Now the simple url mapping looks like this.

 
 
 /config.properties=configPropertyController
 /*=mySpringManagedMessageBroker
 
 

Next step is to configure the controller and a default view resolver. The view resolver uses a resource bundle to connect the views and the classes that generate content.


 
 

The last thing to mention for the spring configuration took me a moment to figure out. Usually when creating a spring application, by default a HandlerAdapter is registered. Since the BlazeDS integration registers it’s own HandlerAdapter, the MessageBrokerHandlerAdapter, we need to register an additional HandlerAdapter to take care of our controller. That is why I added the following line to the spring config.

PropertyController

The classes I added are pretty straightforward. I created a super class called PropertyController. This class implements the Controller interface. It is an abstract class that calls the method to create a Map. This map is stored in the model and we move on to the view with a name propertiesView.
public abstract class PropertyController implements Controller {
 public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
 Map exposedParams = createExposedParamsMap(request);
 return new ModelAndView("propertiesView", "exposedParams", exposedParams);
 }
 abstract protected Map createExposedParamsMap(HttpServletRequest request);
}

ConfigPropertyController

For our case, we mapped the config.properties to the class ConfigPropertyController. The implementation makes use of the provided HttpServletRequest to read information about the server.
public class ConfigPropertyController extends PropertyController {
 protected Map createExposedParamsMap(HttpServletRequest request) {
 Map exposedParams = new HashMap();
 exposedParams.put("host", request.getServerName());
 exposedParams.put("port", String.valueOf(request.getServerPort()));
 // The context root path contains a prefix '/', we have to take that of.
 String contextRoot = request.getContextPath();
 contextRoot = contextRoot.substring(1);
 exposedParams.put("context-root", contextRoot);
 return exposedParams;
 }
}
The last piece of the puzzle is the PropertyView class. This class writes out the file to the client with one of the provided properties per line. Exactly like you’d expect a property file to be.
public class PropertyView extends AbstractView {
 public PropertyView() {
 setContentType("text/plain");
 }
 protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
 Map exposedParams = (Map)model.get("exposedParams");
 Set> entries = exposedParams.entrySet();
 response.setContentType(getContentType());
 for(Map.Entry entry : entries) {
 StringBuilder lineBuilder = new StringBuilder();
 lineBuilder.append(entry.getKey());
 lineBuilder.append("=");
 lineBuilder.append(entry.getValue());
 response.getWriter().println(lineBuilder.toString());
 }
 }
}
Now you can start up the server and test the implementation. Than we continue with the flex client

The Client

On the client side I use Mate, I do not think this changes the implementation of this strategy a lot. Another thing you’ll need is a copy of the spring-ActionScript project. Sorry no maven yet. Get a copy from the site and build it.
http://forum.springsource.org/showthread.php?t=66193
You’ll need this library for easy access to a nice way of loading property files from the server. The next block of code shows some functions that reside in you main flex application file.
[Bindable]
public var properties:Config = new Config();
private var loadedProps:Properties = new Properties();
public function initApp():void {
 loadedProps.addEventListener(Event.COMPLETE, onLoaderComplete);
 loadedProps.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
 loadedProps.load("config.properties");
}
private function onLoaderComplete(event:Event):void {
 properties.host = loadedProps.getProperty("host");
 properties.port = loadedProps.getProperty("port");
 properties.webcontext = loadedProps.getProperty("context-root");
}
First we initiate a load of the file we used in the server side part called config.properties. Responding to the complete event, we set the properties of the Config object using the loaded properties from the server. Next up we initiate the Mate event maps. Notice that we add the properties object to this map under the property props.
In the EventMap we have to add the property called props of type Config. Using this object we can configure the remote obejcts like this.
 
That is about it, now the client knows how to obtain the server config data and with this information it can access the endpoints.
If you want to have a look at the code or try it yourself, have a look at the following project in google code.
http://code.google.com/p/gridshore/source/browse/#svn/trunk/books-overview
Look for the books-flex-mate module to check the current progress of the new implementation. It is by far from finished. As of now you can only login using user/user and logout again.
Hope this can help you program your flex better, or at least have some inspiration to improve your (or mine) code. Comments are welcome
Flex remoting without configuring the client

Comments