Home > Software Development > Developing Java Client to Adobe BlazeDS

Developing Java Client to Adobe BlazeDS

If you develop FLEX with Java backend, you most likely know BlazeDS already. It’s a web application running with Tomcat that exposes Java objects on the server side as services to the Flex Client written in ActionScript. It combines the best of Flex on the client side and Java on the server side. As a result, it becomes one of the most popular architectural styles for web development these days.

It’s less known that you can also develop Java code on the client that consumes the services on the server side. Check out this wiki page by Adobe on the original design. The implementation of Java AMF Client is added to BlazeDS as of July 2008.

Time to learn how to "Google" and manage your VMware and clouds in a fast and secure


Because I had to hack something with my project, I started to look at on how to write Java code to leverage the server side Java. It took me a little while to figure out how it works due to very limited documentation available from Adobe and others. I did find some questions and answers in the Adobe forum, but there is no clear picture especially if you have secured services. Hopefully this post can fill the gap.

How Java AMF Client Works

To allow object remoting, Adobe invented AMF message format. You may wonder, why not XML? Well, I guess Adobe might think XML too verbose and it already had something from previous projects that can be easily reused for BlazeDS project. The AMF format is language neutral. As long as a client can understand the AMF format, it can do object remoting. This is of course no problem for ActionScript which has built-in support.

For Java, the support for AMF on client side has been added in 2008 as mentioned earlier. The basic work flow in Java is as simple as the following code as copied from the design doc:

AMFConnection amfConnection = new AMFConnection();
String url = "http://localhost:8400/team/messagebroker/amf";
Object result = amfConnection.call("remoting_AMF.echo", "echo me1");

Note that I have removed all the try-catch parts so that you clearly see the flow. It really a 4 step flow:

1. Construct a new AMFConnection object

2. Call the connect() method with a URL that expose the service

3. Invoke the call() method. To find out what is available for your call, you want to check out the remoting-config.xml file which is normally in your web application’s WEB-INF\flex sub-directory. Just look for the destination tag there – the id value is what you need. For the method, you can find the Java class for the methods it exposes.

<destination id="remoting_AMF">

4. When you are done, you should close the connection so that related resources are released accordingly.

Secured Services

It’s a little more complicated if the service is secured as defined in following:

<destination id="remoting_AMF">
    <security-constraint ref="authorized" />

In this case, you need to check the security section in the services-config.xml file in the same directory as the remoting-config.xml. The following is a sample snippet:

  <login-command class="org.doublecloud.MyLoginCommand" server="Tomcat">
  <security-constraint id="authorized">

What it says is that the authentication is per client based, and via the customized login implementation with MyLoginCommand which must implement the flex.messaging.security.LoginCommand interface. In the <desitination> part, if you see it includes security as “authorized,” you will need to authenticate your client first. Because it’s per client based, you only need to do once at the beginning.

Your application may have its own login for authentication. It’s different from what is provided by BlazeDS. Even you’ve logged into your application, BlazeDS can still fail you because the above authentication configuration is meant for the BlazeDS. So there could be two layers of authentications if you have a secure application.

Now the interesting question is how the BlazeDS tracks your client? Naturally you would think of the HTTP cookie. That is right, but it’s part of the mechanism. If you use tools like Charles proxy, you may find clientId in request messages and clientIdBytes in response messages. You, me too, may think this is what is used to track a client. It turned out not the case. For one thing I found out, these strings keep changing so it cannot be the tracking token.

After analyzing the messages back and forth a Flex client and BlazeDS, I found out one constant string called DSId in the headers property (NOT HTTP header). It’s sent back from BlazeDS right after it’s pinged. For every consecutive call, you should pass the value back in the AMF message header for tracking purpose.

Now that the flow is clear, let’s summarize the steps with secured application:

1. Send a HTTP GET and retrieve the cookie from the response which has a “Set-Cookie” header. Just get its value and you will have a cookie like:

2. Create a AMFConnection object and set its Http headers:

this.amfConn = new AMFConnection();
amfConn.addHttpRequestHeader("Cookie", cookie);
amfConn.addHttpRequestHeader("Content-type", "application/x-amf");

3.     Call connect() method with exposed URL

4.     Ping the client for DSId

CommandMessage cmdMsg = new CommandMessage();
cmdMsg.setHeader(Message.FLEX_CLIENT_ID_HEADER, "nil");
Object obj = amfConn.call(null, cmdMsg);
AcknowledgeMessage resp = (AcknowledgeMessage) amfConn.call(null, cmdMsg);
String dsId = resp.getHeader(Message.FLEX_CLIENT_ID_HEADER);

5. Login your application if you application requires login. In this case, the login method must not be secured by BlazeDS. You can call it just as in previous section. Also, you should use HTTPS because of this.

6. Invoke the call with CommandMessage.LOGIN_OPERATION command,

CommandMessage cmdMsg = new CommandMessage();
cmdMsg.setBody(cred); //you can hash username +":"+ password using BASE64
cmdMsg.setHeader(Message.FLEX_CLIENT_ID_HEADER, dsID);
cmdMsg.setHeader(Message.ENDPOINT_HEADER, "my-secure-amf");
AcknowledgeMessage ack = (AcknowledgeMessage) amfConn.call(null, cmdMsg);

7. From this point, you can call any other secured methods of remote Java object.

8. When you are done, make sure to call close() to release resources.

A Bug in BlazeDS

While hacking around, we found a potential bug in the flex.messaging.services.AuthenticationService class.

public Object serviceCommand(CommandMessage msg)
  LoginManager lm = getMessageBroker().getLoginManager();
  switch (msg.getOperation())
    case CommandMessage.LOGIN_OPERATION:
      if (msg.getBody() instanceof String)
        String encoded = (String)msg.getBody();
        Object charsetHeader = msg.getHeader(CommandMessage.CREDENTIALS_CHARSET_HEADER);
        if (charsetHeader instanceof String)
          decodeAndLoginWithCharset(encoded, lm, (String)charsetHeader);
          decodeAndLoginWithCharset(encoded, lm, null);
    case CommandMessage.LOGOUT_OPERATION:
      throw new MessageException("Service Does Not Support Command Type " + msg.getOperation());
  return "success";

I will leave it to you to guess the bug and how to fix it. (Hint: what if your message body is not a string.)

Last but not the least, many thanks to my colleagues who helped and made the hacking fun!

Categories: Software Development Tags: ,
  1. Kamil Szukalski
    November 7th, 2013 at 10:21 | #1

    Hi! Thx for this great tutorial, however I still have got some problems and I am not able to connect to my local blazeds. I do not understand but even after successful CommandMessage.LOGIN_OPERATION I am getting this error:

    data: ASObject(1400383465){message=An Authentication object was not found in the SecurityContext, rootCause=ASObject(1971608782){message=An Authentication object was not found in the SecurityContext, localizedMessage=An Authentication object was not found in the SecurityContext, cause=null, authentication=null, extraInformation=null}, details=null, code=Client.Authentication}

    I think that my CommandMessage.LOGIN_OPERATION is successful since I am getting correct AcknowledgeMessage with specific role for the user in my app.

    Any idea what I can be missing?:) Please help :)

  2. November 8th, 2013 at 00:29 | #2

    Hi Kamil,

    Glad you like this writing. It’s been a while since I touched the BlazeDS with Java, therefore I don’t have clear clue on what went wrong, neither do I have the setup to refresh my memory. Given the problem, you may want to use debugger to dig into the code.

    Good luck!


  3. Kamil Szukalski
    November 8th, 2013 at 03:46 | #3

    What I have discovered, when I have got

    and NOT set cookie – then my script works

    but when I change to

    and set cookie – then my script does not work

    For per-client-authentication=”true” (and that’s how my app is built) neither option is working for secured commands. Maybe this help/remind you sth? If not, then thx for any feedback :) As a cookie I get this “JSESSIONID=252655045982247CA86E4EF47794E5F2; Path=/BlazeDS_XXX” and I set it like this: amfConnection.addHttpRequestHeader(“Cookie”, cookieWithJSessionID);

  4. Kamil Szukalski
    November 8th, 2013 at 04:45 | #4

    I think that my problem is connected with getting appropriate JSessionID – with each call of standard url.openConnection() i get different JSessionID – so none of them can be connected with my new amfConnection. How to get cookie for amfConnection?

  5. Kamil Szukalski
    November 13th, 2013 at 09:35 | #5

    !!! SUCCESS !!!
    I leave this part of code for people who will have got similar problem :) My problem was in understanding per-client-auth algorithm. After successful CommandMessage.LOGIN_OPERATION, developer should NOT call services with basic pattern like amfConnection.call(“nameOfService.nameOfMethod”, “param1”), but rather in following way:

    RemotingMessage call = new RemotingMessage();
    call.setHeader(“DSId”, “” + dsId);
    AcknowledgeMessage result = (AcknowledgeMessage) amfConnection.call(null, call);

    In the body of result variable, we are able to get proper response from BlazeDs:) I hope this will help others :)

  6. November 15th, 2013 at 14:32 | #6

    That is very cool Kamil! Thanks for sharing the trick here.


  7. Kevin
    April 9th, 2014 at 13:52 | #7

    Hi Steve,

    Great sample, thanks! Do you have streaming client samples as well? It seems to be the way streaming data is processed is quite different from AMF and I have not been able to make a success there.


  8. Kevin
    April 9th, 2014 at 13:54 | #8

    Hi Steve,

    Great sample, thanks! Do you have streaming client samples as well? It seems to me the way streaming data is processed/decoded at client is quite different from polling, and I have not been able to make a success there.


  9. April 9th, 2014 at 17:11 | #9

    Hi Kevin,

    Glad you like it. Sorry that I haven’t done streaming client after the sample was done because I moved onto other projects. Good luck!


  1. No trackbacks yet.