Friday, October 3, 2008

REST + JSON + AMF

So...I was asked to investigate what will it take to output data in AMF to an existing REST endpoint. The idea is that, with just a path info switch, the endpoint can output XML, JSON or AMF i.e. http://server/rest/service/json, http://server/rest/service/amf. And no, a direct BlazeDS integration is not an option :-( So after looking at the BlazeDS source code (you gotta love open source :-) I homed in on the Java15Amf3Output class. It take an output stream as a property and has a writeObject method. Cool ! So given an Address instance:

package com.esri.webamf;

import java.io.Serializable;

public class Address
implements Serializable
{
private String m_addr;
private String m_city;

public Address()
{
}

public String getAddr()
{
return m_addr;
}

public void setAddr(final String addr)
{
m_addr = addr;
}

public String getCity()
{
return m_city;
}

public void setCity(final String city)
{
m_city = city;
}
}

I can write it to the servlet output stream as follows:

private void writeAMF(
final HttpServletRequest httpServletRequest,
final HttpServletResponse httpServletResponse
) throws IOException
{
final Address address = new Address();
address.setAddr( httpServletRequest.getParameter("addr"));
address.setCity( httpServletRequest.getParameter("city"));
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Amf3Output amf3Output = new Java15Amf3Output(new SerializationContext());
amf3Output.setOutputStream(baos);
amf3Output.writeObject(address);
amf3Output.writeObjectEnd();
amf3Output.flush();

httpServletResponse.setContentType(MessageIOConstants.AMF_CONTENT_TYPE);
httpServletResponse.setContentLength(baos.size());
baos.writeTo(httpServletResponse.getOutputStream());
}

On the client side, I used a URLStream instance with an AMF3 object encoding to HTTP GET the result as an ActionScript object as follows:

private function load() : void
{
var urlRequest : URLRequest = new URLRequest( "http://localhost:8080/webamf/rest/amf" );
var urlVariables : URLVariables = new URLVariables();
urlVariables.addr = addr.text;
urlVariables.city = city.text;
urlRequest.data = urlVariables;

var urlStream : URLStream = new URLStream();
urlStream.objectEncoding = ObjectEncoding.AMF3;
urlStream.addEventListener(Event.COMPLETE, completeHandler );
urlStream.load( urlRequest );
}
private function completeHandler( event : Event ) : void
{
var urlStream : URLStream = event.target as URLStream;
address = urlStream.readObject() as Address;
}

Where Address is tagged as a remote class aliased to the server side Address class:

package com.esri.webamf
{
[Bindable]
[RemoteClass(alias="com.esri.webamf.Address")]
public class Address
{
public var addr : String;
public var city : String;

public function Address()
{
}
}
}

Cool ?

4 comments:

gembin said...
This comment has been removed by the author.
gembin said...

yes it's cool
but how to do POST or PUT?

thunderhead said...

In in the above example, I'm using a URLStream to GET the data.

Anonymous said...
This comment has been removed by a blog administrator.