Cross-Domain Ajax support for ActiveMQ

In this post I will try to summarize a case-study for implementing Cross-Domain Ajax support for ActiveMQ.

Use Case

In the current implementation of Ajax support for ActiveMQ, you can use JavaScript to consume and send messages, but only directly in your application. This stands mostly due to “same-domain” restriction of the XmlHttpRequest calls.

This makes impossible to use those messages in “trusted” applications and make them all use the same underlying mechanism. For example, you might want to create an embeddable Ajax message browser that could be used in various related applications to allow “operators” (non-technical people) to work with messages in certain queues and topics.

Possible techniques

There are many techniques that are used today to solve this problem. Every one of them has its strengths and weaknesses. So here I will try to summarize all of them and find the best fit for messaging purposes and current ActiveMQ implementation.

1. Proxy

This technique assumes that you put a server-side script on your client application. The purpose of this script is to get your local XmlHttpRequest calls and forward it to the “original” provider of the Ajax service.
While this solution is perfectly valid, it is a little bit clumsy as a “general-purpose” solution, because we must provide proxies for many languages (Java, Ruby, PHP, …) and developers must find a way to “install and configure” this proxy in their application.

2. JSON and dynamic Script tag

With this technique you create a script tag that calls a remote JS script and define a callback function that script should call when it finishes. The remote script returns a result in JSON format and calls a function. In this way we have achieved a kind of web service functionality without using XML and XMLHttpRequest.
The only problem with this solution is that it is impossible to do POST method calls with it, so it is hard to send messages with it.
We can implement this solution for those who are only interested in consuming messages from arbitrary Ajax client.

3. FlashXMLHttpRequest

Thanks to the Julien Couvreur’s excellent work (http://blog.monstuff.com/FlashXMLHttpRequest), there is another solution that is the most complete and would suit given requirement the best.
It is basically a Flash proxy for HTTP calls that could be used directly from JavaScript.
It supports both GET and POST methods, does not require any server-side proxy and could be designed to be compatible with current ActiveMQ Ajax API.
The user would use the same approach as now

<script type="text/javascript" src="https://example.com/amq.js"></script>
<script type="text/javascript">amq.uri='http://example.com/amq';</script>

We would detect whether it is a cross-domain or a local call case. If it is a local call everything would be the same as now. In case of cross-domain usage we would include all necessary files and instantiate remote version of the amq object.

Implementation

From now on, I will mostly focus on the third solution (FlashXMLHttpRequest) and talk about design issues.
Besides detection of remote access and inclusion of appropriate libraries, there are several more things that should be changed on the server-side of the ActiveMQ Ajax implementation.
First of all, FlashXMLHttpRequest does not support setting of arbitrary request headers. The only supported header in this moment is content-type. The current ActiveMQ Ajax implementation use request parameters to pass parameters between Ajax client and server.
I thought a bit how we can deal with this issue and came with the solution that not only solves this issue, but also could make the whole implementation much more flexible and extensible in the future.
It is practically a combination of methods two and three: JSON and Flash used together.
The solution is to use JSON and send JavaScript objects between client and server. The MessageListenerServlet would make this special handling of requests that has text/javascript content type. It could parse the JSON object and use all necessary details from it (destination, priority, content …). On the other hand, messages that are received by the client could be transformed into JavaScript objects and used directly further on. I have tried some experiments on this particular topic and it is evident that it could be easily built.
In this way, we have the best of the solutions (POST method of the Flash client and JSON format for the messages). Also, since messages now are objects in JavaScript world too, we can extend them and build our solutions on them much easier.
For example, we can now easily add support for MapMessages and client acknowledgment mode, to name two.

Security

In the FlashXMLHttpRequest technique, the security is handled by the crossdomain.xml file. I’m aware that this solution also has some security problems (http://shiflett.org/archive/263), but since we are controlling the server-side of the solution we can implement various additional security mechanisms on top of that.
Also, I see this solution as primarily used in private (not public) domain and applications that knows who should do they trust. So all this should be taken cared of in the final implementation. Of course, everything is open to discussion.

Conclusion

This post is intended to be a conversation starter. Any comments and ideas are welcome.

Leave a comment

Your email address will not be published. Required fields are marked *