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:

  1. This comment has been removed by the author.

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

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

    ReplyDelete
  4. This comment has been removed by a blog administrator.

    ReplyDelete