Invoking OpenX api from Flex

For the last several months I was playing with OpenX, an open source ad server written in PHP.  You can interact with OpenX in two ways: first by using the admin graphical interface, second by using API calls – most of the UI functionality can be programmatically reproduced.

OpenX is exposing its API through XML-RPC and they have a couple of examples on their website how to invoke the API from PHP, Java and Ruby. In my case I was trying to display some statistics without going through a middleware, so I started to investigate how can I do it from Flex. It turned out to be quite easy – one can use the AS3 RPC written by Akeem Philbert, with a small modification. The following steps should be done:

a) download the source code of the library from this location (http://code.google.com/p/as3-rpclib/)

b) you have to fix a small issue in the class com.ak33m.rpc.xmlrpc. XMLRPCObject  (compatibility issue between SDK’s). The overloaded methods setCredentials and setRemoteCredentials should receive another parameter, called charset.

c)create the objects mapping the OpenX structures (advertiser, campaign, zone etc) and invoke the exposed methods

I did these steps and I created this Flash Builder project – you can import it into your workspace and change the file ServerConfig.as accordingly.

In my example I have just a couple of operations like login, displaying and creating advertisers. It can easily be extended in order to support the whole OpenX api.

Next post on OpenX will be about displaying the ads on your website, from Flash and HTML.

Java exceptions and Flex

I’ve seen some articles on this subject but I have not found one dealing with all cases (webservices, BlazeDS, BlazeDS and Spring, data management). Also the approach for BlazeDS is different than the one used with Spring/BlazeDS integration, and this thing can be a little bit confusing for a beginner.

Let’s assume that you have a layer of services that should be invoked from your Flex application. You can expose these services as web services or as remote methods. Or you can use data management. The Java methods may throw errors and you want to display them in the Flex application.

For simplicity I will use a very short method as an example. The method signature is :

public String returnResults() throws DatabaseDownException;

There are four main use cases:

a)You have to write a webservice to return the result as XML. For example:

<?xml version="1.0" encoding="UTF-8"?>
<data>
<result>
</result>
</data>

In this case you will need to enhance your XML to add a structure for keeping error messages – like this:

<?xml version="1.0" encoding="UTF-8"?>
<data>
<result>
</result>
<error>
</error>
</data>

When building the XML the <error> body is going to envelope the exception message. Of course more information can be added, including exception type, severity, and so on. The same approach should be used also when working with SOAP services

b)You plan to use BlazeDS and Java remoting

In this case things are going to be easier,  because BlazeDS is able to automatically serialize the thrown exception and you can find the serialized exception in the FaultEvent object. Assume that you have the Java exception declared below. It extends the RuntimeException and it has a getter method for a custom field.

public class DatabaseDownException extends RuntimeException{
private String customField;
public String getCustomField(){
return customField;
}
}

The Flex code declares a remote object and registers a handler (which is also included) for failure.

<mx:RemoteObject id="test" destination="testDestination" result="resultHandler(event)" fault="faultHandler(event)"/>
private function faultHandler(event:FaultEvent):void{
var exception:Object = event.fault.rootCause;
Alert.show(exception.cause);
Alert.show(exception.localizedMessage);
Alert.show(exception.message);
Alert.show(exception.customField);
}

There are four fields in the serialized exception. The first three are inherited from the Throwable object, the last one is declared in your exception. It is interesting to note that you need not have a pair of set/get function in order to have your property serialized. The Throwable object is the only object in which  it is enough to have get methods in order to serialize the values (you can take a look at flex.messaging.io.ThrowableProxy to check that).

The only drawback is that you are working with untyped objects..if you don’t like that you can throw instead instances of flex.messaging.MessageException. This Java class is part of the BlazeDS and it will be deserialized using the class mx.messaging.messages.ErrorMessage (obtained from the event.message property).

You can add your custom data in the MessageException class using the extended property. For example:

MessageException messageException = new MessageException();
HashMap<String,String> map = new HashMap<String,String>();
map.put("clientName", "JOHN");
map.put("clientSurname", "MASTER");
messageException.setExtendedData(map);
messageException.setCode("ACCOUNT_DISABLED");
throw messageException;

And on the Flex side:

private function faultHandler(event:FaultEvent):void{
var errorMessage:ErrorMessage = event.message as ErrorMessage;
trace(errorMessage.extendedData.clientName);
trace(errorMessage.extendedData.clientSurname);
trace(errorMessage.faultCode);
}

You probably do not want to have an explicit dependence between your service layer and the BlazeDS libraries, so in this case you should build a delegate on top of it, which will also act as an exception translator.

c)Using Spring BlazeDS Integration

You have several benefits when using Spring BlazeDS integration, and if your middle tier is already using Spring it’s a must. The benefit related to exception handling is the exception translator mechanism. This translator will catch all the exceptions thrown from the services invoked from Flex and you can translate them into something more meaningful for the client.

First you need to declare the exception translator:

<bean id="exceptionTranslator" class="com.test.exception.ExceptionTranslatorImpl" />
<flex:message-broker services-config-path="/WEB-INF/flex/services-config.xml">
........
<flex:exception-translator ref="exceptionTranslator" />
</flex:message-broker>

The exception translator is below:

public class ExceptionTranslatorImpl implements ExceptionTranslator{
//handles all
public boolean handles(final Class<?> clazz){
return true;
}
public MessageException translate(final Throwable throwable){
if (throwable instanceof DatabaseDownException){
MessageException exception = new MessageException();
exception.setCode("FATAL_DB_DOWN");
return exception;
}
if ...........//check another things
}
}

Note that in the current version of Spring/BlazeDS integration it is mandatory to have an exception translator, otherwise the original error is going to be swallowed and you will receive some generic error.

d)Using data management

The same approach from point c) applies here. Basically your assembler – which is going to invoke some service to obtain/create data – will take care of translating the exceptions into something meaningful for the client. I wrote some time ago a short post about that here.

Note: this article was translated also in Belorussian (thanks Patricia), you can find it here.

Flex Data Services, Hibernate and Eclipse – Mike Slinn book

A lot of books about Flash, Flex, ActionScript and Java are available on the market and some of them are really good. However there are still very few books related to Flex and Java integration – best practices, frameworks, performance issues, patterns and anti patterns. Mike’s book fills a gap here, in talking primarily about the two Adobe products: BlazeDS and LiveCycle Data Services. I’ve met few people who really know well these products well, and I think that this book can help people get a better understanding. Flex and the other RIA technologies should improve not only the user experience/interaction but also the developers life  – making it much easier with – increased productivity, no more hacks and no more stateless clients. For that you need a strong platform both on the client and server side and LiveCycle Data Services can fulfill that.

The book comes with a tool written in Flash that can help you edit configuration files visually. Personally I would like to see an Eclipse plugin also – but considering that the tools for integrating Flash Player with Eclipse already exist I guess it’s possible in future.

The book is in early release – it can be ordered here.

Some internals related to Flex and remoting

When I started working with Livecycle Data Services and Java remoting I was afraid of doing too many remote calls at one time because of the network latency – if the network latency is 100ms and you do ten remote calls in order to fill a panel with data you will lose (10/maximum no of parallel connection supported by the browse*0.1) seconds for requests  . At least this is what I thought, taking into account my experience with Ajax.

However I found that this is not the case when doing remoting using the AmfChannel (which is backed by flash.net.NetConnection). In this case all your remote calls are put in a queue, and then all this request are grouped in a single HTML post. So no ten calls, only one – you can check that using a proxy like Charles.

It is important to note that this happens only when you use channels backed by flash.net.NetConnection – if you use HttpChannel which is backed by flash.net.URLLoader you will have 10 different calls.

So I can conclude that you should not be worried that you have too many HTTP requests (listed as the first optimization by Yahoo -check this link) when using remoting.

Passing URL parameters to a Flash application

I have identified three cases in which you may want to extract parameters passed via the URL to your Flash application:

a)The URL is something like this: http://www.test.com/page.html?parameter=test. The SWF file is included in the HTML page.

Solution: Use the ExternalInterface to extract the data from URL. It’s not a nice solution but I do not know another option. The code is below:

private function readParameters():Object{
 var params:String =
  ExternalInterface.call("window.location.search.substring");
 return (params?(new URLVariables(params.substring(1))):null);
}

b)The URL is something like this: http://www.test.com/page.jsp?parameter=test. The SWF is included in the JSP page. The JSP will be rendered to produce HTML output.

The same solution from a) works. However, it is also possible to read the parameters from the Java code with request.getParameter() and add them to AC_FL_RunContent.. invocation.

    AC_FL_RunContent(
            "src", "test_test",
            "width", "100%",
            "height", "100%",
            "align", "middle",
            "id", "test_test",
            "quality", "high",
            "bgcolor", "#869ca7",
            "name", "test_test",
            "flashvars", "paramOne=test1&param2=test2",
            "allowScriptAccess","sameDomain",
            "type", "application/x-shockwave-flash",
            "pluginspage", "http://www.adobe.com/go/getflashplayer"
    );

Now you can read the parameters with the following code:

var params:Object = Application.application.parameters

c)The SWF is called directly. for example http://www.test.com/myswf.swf?parameter=test

In this case you can read the parameters again using the code from b)

var params:Object = Application.application.parameters

Using AMF and Web Services

You can pack and send your data using AMF even if you don’t use the remoting services. In this post I will show several ways to do that using HTTP services. Why would you want to do that ? There are organizations or departments that expose only REST and SOAP services and it can be hard to persuade them to add the remoting services. In this case, when using web services, you have two solutions: you can create XML from your object graph (and for that you’ll have to write extra code) and apply a compression algorithm on it, or you can apply AMF serialization on the object graph, add the resulting byte code in the service body, and deserialize the AMF format on the client side.

Below is a sample how to do that. First, the Java code on the server:

    public void service(ServletRequest arg0, ServletResponse response)
            throws ServletException, IOException {

        Product product = new Product("name","description");        

        SerializationContext context = new SerializationContext();
        context.instantiateTypes = true;

        ByteArrayOutputStream baos = new ByteArrayOutputStream(64*1024);
        Amf3Output amf3Output = new Amf3Output(context);
        amf3Output.setOutputStream(baos);

        amf3Output.writeObject(product);
        amf3Output.flush();

        response.getOutputStream().write(baos.toByteArray());
    }

On the client you have two options. The easier one is to use an URLLoader.

        private function loaderCompleteHandler(event:Event):void {
            //rebuild the object                            
            var product:Product = loader.data.readObject();
        }

        function sendData(event:Event){
            var request:URLRequest = new URLRequest("/test/loaddata/");
            loader = new URLLoader();
            loader.dataFormat = URLLoaderDataFormat.BINARY;
            loader.load(request);
            loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
            loader.addEventListener(Event.COMPLETE, loaderCompleteHandler);
        }

If you want to use an HTTPService you have a problem, because by default it does not handle binary data. However it’s easy to extend the class and to add binary support.

    public class HTTPServiceExt extends HTTPService{
        protected static var binaryChannel:Channel;
        protected static var binaryChannelSet:ChannelSet;
        public var binaryData:Boolean;

        public function HTTPServiceExt(){
        }
        override public function send(parameters:Object = null):AsyncToken{
            if (( useProxy == false ) && (binaryData)){
                if ( binaryChannelSet == null ){
                    var dcs:ChannelSet = new ChannelSet();
                    binaryChannel =
                    new DirectHTTPBinaryChannel("directhttpbinarychannel");
                    dcs.addChannel(binaryChannel);
                    channelSet = dcs;
                    binaryChannelSet = dcs;
                }
                else if ( channelSet != binaryChannelSet ){
                    channelSet = binaryChannelSet;
                }
            }
            return super.send(parameters);
        }
    }

The class DirectHTTPBinaryChannel is taken from Anirudh Sasikumar’s blog. It extends DirectHTTPChannel and it configures the internal URLoader to work with binary data.

Now you have an HTTPService class that knows how to receive binary data also. In order to use it you have to add the binaryData parameter:

    function resultCall(event:ResultEvent):void{
       var product:Product = event.result.readObject();
    }
    <local:HTTPServiceExt binaryData="true" id="srv"
        url="/test/loaddata/"
        result="resultCall(event)"
        fault="faultCall(event)"/>

That’s all. You can refine the code; for example you may want to create only one URL for all the resources and to pass parameters, or you can use SOAP services and add the AMF binary format as an attachment.

I also uploaded a Flex/WTP project here containing all the source code.

Using Hessian and Flash player

I created my first application using Hessian last week and I thought I’d write about the main differences between using AMF and the Hessian protocol for remoting. You can also download my sample project here – it’s the same Hello World sample with PureMVC from a previous post modified to work with Hessian.

In comparing AMF and Hessian I’ll start with the server side.

a)Server side libraries and configuration

If you plan to use AMF you will need to use BlazeDS, LiveCycle Data Services  or another product (GraniteDS, WebOrb etc). If you only need remoting you can strip out most of the jars, but you will still need more than 800 kbytes. For Hessian you need only one jar – about 300 kbytes. Also for AMF you will need to declare a servlet (MessageBroker) in the web.xml file.

b)Exposing your Java methods

When using BlazeDS any object with a public constructor can be a remoting point, and you will have to write an entry in a configuration file:

<destination id=”HelloService”>
<channels>
<channel ref=”my-amf”/>
</channels>
<properties>
<source>
org.puremvc.server.java.helloworld.services.HelloService
</source>
<scope>application</scope>
</properties>
<adapter ref=”java-object” />
</destination>

You will also have to define the channel – to specify how you intend to communicate between the client and server. For remoting the AMF channel is the preferred solution

<channel-definition id=”my-amf” class=”mx.messaging.channels.AMFChannel”>
<endpoint url=

http://{server.name}:{server.port}/hellopuremvc_blaze/messagebroker/amf

class=”flex.messaging.endpoints.AMFEndpoint”/>
</channel-definition>

For Hessian you have to write a class extending HessianServlet containing all the methods which can be invoked. After that you add this servlet in web.xml

<servlet>
<servlet-name>model</servlet-name>
<servlet-class>HessianSerializeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>model</servlet-name>
<url-pattern>/model/*</url-pattern>
</servlet-mapping>

Another difference is that in the Hessian case all the Java objects used as value objects should implement the Serializable interface

c)Client side invocation

For AMF you do not need any external libraries because the serialization and deserialization is done natively in Flash Player. However for Hessian you will need a library and latest version (3.2) is about 500 kbytes.

From a programming point of view is the biggest difference is that for Hessian case you will need to have the AS class and the Java class in the same location (package +name) if you want to have automatic serialization/deserialization. You can use the “RemoteClass” tag also for Hessian, but it works only in one direction (from Flex to Java), at least this is what I noticed. Otherwise the call looks the same:

AMF:

service = new RemoteObject();
service.destination = “HelloService”;
service.requestTimeout = 3;
var call:Object = service.sayHello(name);

Hessian

service = new HessianService();
service.destination = “/hellopuremvc_hessian/services/”;
service.requestTimeout = 3;
var call:Object = service.sayHello(name);

The destination definition is a little bit tricky – for AMF it should be the same as the one defined in services.xml, for Hessian it should be the same as the servlet mapping from web.xml

<servlet>
<servlet-name>services</servlet-name>
<servlet-class>org.puremvc.server.java.helloworld.servlet.HelloServiceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>services</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

d)Performance and other considerations

As I wrote in a previous post Hessian serialization from the server side is faster than AMF one, and the compressed data almost has the same size. However on the client side the AMF is the clear winner because of the native support provided by Flash Player. Also the Hessian library for the client is quite big.

Below are the links describing the mapping between ActionScript and Java types:
AMF
Hessian

Hello world – PureMVC demo

Some time ago I was reading PureMVC documentation and I decided to write a small application to better understand the concepts. I wrote the smallest possible example (which has also server communication) – a Hello world application. It has a text field where you can type your name and a Send button. When you click Send, a message with your name is sent to the server, and the server will reply with a “Hello” message. The program is inspired by the Hello world version written with Cairngorm.

You can download the full Flex Builder project here – for the server part I used BlazeDS. Feel  free to use or modify the source code as you want.

URI has an authority component error

Yesterday I was with some students doing some labs from Duane’s training course when I saw this error “URI has an authority component” – it appeared when we tried to execute an AIR application. After some time we figured out the reason: the workspace was saved on a network shared folder – we mapped the network path with a drive letter and we got rid of this strange error.

Remoting, XML, AMF, Hessian and Deflate algorithm

I’m a big fan of using remote calling whenever possible to bring the data from a Java server into a Flex application, not only for performance reasons but also because the code is much cleaner. Yesterday, I implemented a quick benchmark to test both approaches (remote versus a service returning xml) – results are bellow.  You can also download the project here (it’s created in Intellij, and you will also need Java persistence libraries). It’s a quick benchmark and not a benchmark framework so the code is no production quality. I’ve tried to eliminate the time spent by the garbage collector and the times for the benchmark are taken into consideration only after the Hotspot optimizations of the code.

Some details about my benchmark: I have three objects (Company objects havea bidirectional 1-n relation with an Employee objects and the Employee has a n-1 relation with a Town object). I read the data from a MySql database using Hibernate(I have about 3 Companies, 1000 Employees, and 5 Towns).

For the XML case I’m doing a conversion from the Java objects to XML, and optionally I have also included a ZIP compression. For the remote case I tested both AMF3 compression and Hessian. I tested only the algorithms (not the time spent the data from the application server) because I think that’s the most important thing.

The results are interesting, the most time is spent in XML conversion (using DOM4J). I will try to use also another XML library, maybe that time can be reduced a little . The results prove again that the binary formats (AMF3 and Hessian) are a very good option when sending data to the Flex client…note that even the compressed XML is not much smaller than the binary format.

Results table below. My system is a Lenovo laptop, CORE 2 Duo, 2.4Ghz

Avg Time (microseconds) Data size (kbytes)
AMF3 9945 28
Hessian 4675 29
XML 22064 158
XML+Deflate 27336 18

Note: the difference between AMF and Hessian depends a lot on the input data. For example if you have more repetitive data then AMF tends to be more efficient than Hessian on data size. I will try in the future to create a mini benchmark framework with different sets of data.