Archive

Posts Tagged ‘json’

Appcelerator Remote Routes for Service Integration

October 5th, 2008 Andrew Zuercher No comments

Problem definition

A few weeks ago i started a thread on the Appcelerator development network about remote routes. The thread got a bit of attention and ultimately meant different things to different people.

web 1.0 transformations

When I get in front of customers today that have an existing web solution in place, they tend to ask some simple questions:

  • What do I have to do to implement a service in <backend framework>?
  • I’ve already got a bunch of web services, can I use them as is?
  • My website has a traditional web 1.0 implementation, will i have to throw away and start over?

Primary focus: cost to implement seems to be the main chasm for them to hurdle.

REST zealots

A bunch of the developers out there are jazzed about building RESTfull services to remotely expose an endpoint for integration. Re-using these endpoints is a natural fit for them and paramount to their needs.

Primary focus: A clean single place to define their services.

back end framework architects

Then there are the framework guys that are out there that have the need to add Appcelerator to extend their portfolio. Recently I helped out with implementing an Appcelerator service for grails. To facilitate the framework integration I write a similar service broker in grails much akin to what we have done for the other platforms. The controller would discover the Appcelerator services written in grails and then invoke them directly. The downside is that:

  • grails developers like to integrate at the controller level and not the service level
  • grails itself makes responding to and rendering JSON very easy
  • grails already has routing and discovery built into the framework

Primary focus: not duplicating existing framework functionality in a way that is consistent with their architecture

Previous approaches

In the past I’ve prescribed a 4-tiered strategy for those that are out there that are interested in integrating their existing application using Appcelerator;

  • create new Appcelerator-specific remote services that reuse existing code inline if possible
  • use an ESB to route to your existing services
  • use the app:http written by Mr. Hashemi as mash-up in the client
  • do not use remote services, but allow Appcelerator to add richness to your application locally in the browser

Solution

Instead of writing remote services that are Appcelerator specific and restrictive, an implicit contract is adhered to. This means that back end services can be written in any language or platform so long as they are able to consume and render in an approved format (for example ‘application/json’).

Traditional

Here is a simple example for a traditional service.

class MyService &lt; Appcelerator::Service
Service 'order.create.request', :create_order, 'order.create.response'
 
def create_order
order = Order.new(params["amount"])
order.save
{'success'=&gt;true, 'id'=&gt;order.id}
end
end

Using remote routes

And now we make use of controllers as well as remote routes. Here is the controller

class OrderController &lt; ApplicationController
def create
order = Order.new(params["amount"])
order.save
respond_to do |format|
format.json { render :json =&gt; {:success =&gt; true, :id =&gt; order.id} }
end
end
end

And now in the client we include the following in our javascript (there are a ton of ways to implement this, but here is an example for now)

	$MQR('r:create.order.request','/order/create','post',
'r:create.order.response');

trade offs

Item Remote Routes Appcelerator Service app:http
Web controllers Yes No, must be appcelerator services. Yes
Message Mapping Yes, client side as javascript to define routes. Concise and not too terribly tedious and can be done in exactly one place. Server side using annotations to map methods to message types. Yes, client side widget declarations per message type.
Message Multiplexing One-2-One: a given request message is associated with a single response message and are processed one at a time. Many-2-Many: this is a big upside for the existing service brokers is that groups of messages can be delivered to the back end at a given time and different types of messages can respond to them One-2-One: a given request message is associated with a single response message and are processed one at a time.
Service Endpoints Multiple can be supported, the target url is an aspect of the message mapping Fixed, all requests go through specifically one exposed endpoint (service broker) Multiple can be supported, the target url is an aspect of the message mapping
External Services Yes No Yes
Serialization Up to back end service to implementor Appcelerator remote service takes care of it for you Up to back end service to implementor

Wrap up

Understanding the trade-offs for the different service routing opportunities should be considered when you architect your solution. At the core of it, Appcelerator provides you with options and leaves that decision up to you, empowering you to make that choice for yourself.

this blog has beeen cross-posted at http://www.appcelerant.com/appcelerator-remote-routes-for-service-integration.html

Technorati Tags: , , ,

Categories: announcements Tags: , , ,

JSON serialization with appcelerator java services

February 8th, 2008 Andrew Zuercher No comments

Using Model Objects

The issue of serializing/transforming model objects is not new, heck I’ve been doing this for quite some time:

  • rmi (ejb/corba)
  • xml (jms, soap, etc..)
  • json

JSON is not the only way to serialize objects for web2.0 applications, but its the most abundant and heavily used throughout our framework. Doing this is actually really easy to do with appcelerator IModelObejects. Our IModelObjects can easily be used along with hibernate for persistance, but lets leave that for later for now. When you define your Model classes, there are some very simple things to keep in mind:

  • annotate your attributes with @MessageAttr
  • have your class implement IModelObject

Here is a simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class User implements IModelObject, Serializable {
  private static final long serialVersionUID = 1L;
 
  @MessageAttr
  public String name;
 
  public void setUsername(String username) {
    this.username = username;
  }
 
 public void setPassword(String password) {
   this.password = password;
  }
 
  ...
}

Unit test it

Now to test the rendering of our object to JSON with a simple junit test…. As you can see, we leverage the Appcelerator framework to serialize our objects to JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ForumTest extends TestCase { 
 
public void testSimple() {
  User user = createUser();
  Message message = new Message();
  JSONMessageDataObject data = new JSONMessageDataObject();
  message.setData(data);
  message.getData().put("user", user);
  message.getData().put("count", 1);
  String messagestr = data.toDataString();
  assertEquals(messagestr,"\"user\":{\"password\":\"pwd\",\"threads\":0,\"fullName\"
  :\"antewew\",\"username\":\"azuercher\",\"state\":\"mystate\",\"email\":\"email\",
  \"posts\":0,\"id\":0},\"count\":1}");
}
 
private User createUser() {
  User user = new User();
  user.setEmail("email");
  user.setFullName("ante wew");
  user.setId(new Long(0));
  user.setPassword("pwd");
  user.setPosts(new Long(0));
  user.setState("mystate");
  user.setThreads(new Long(0));
  user.setUsername("azuercher");
  return user;
}
 
}

Dealing with recursion

Whats always a bit of a tangle is understanding how to deal with the recursive/circular relationship.
If you take a look at JSONObject you will see 2 overridden methods for createBean

1
2
public static JSONObject createBean(IModelObject object,MessageAttr parentAtt, String context,String[] parentSuppres,int level, int maxlevels)
public static JSONObject createBean(IModelObject object)

The latter is obviously a bit more simple, but the former is where the power is. In the MessageAttr annotation, you can provide the suppress attribute which is a comma separated list of aggregates (using bean.name notation to not serialize). This is used for attributes in your IModelObject implementation where the association is with another IModelObject. The following model is for a forum object model where the following aggregate hierarchy exists:

1
2
3
* Forum
** ForumThread
*** Post

In the snippet below, I’ve omitted the getter/setter methods for the aggregates for simplicity.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class User implements IModelObject, Serializable {
  @MessageAttr (suppress="user,thread.lastPost")
  public Post lastPost;
}
 
public class Post implements IModelObject, Serializable {
  @MessageAttr(suppress="lastPost,forum.lastPost")
  public Forumthread thread;
 
  @MessageAttr (suppress="lastPost")
  public User user;
}
 
public class Forumthread implements IModelObject, Serializable {
  @MessageAttr (suppress="lastPost")
  public Forum forum;
 
  @MessageAttr (suppress="thread,user.lastPost")
  public Post lastPost;
}
 
public class Forum implements IModelObject, Serializable {
  @MessageAttr (suppress="thread.forum,thread.lastPost,user.lastPost")
  public Post lastPost;
 
}

Rolling your own serialization

Assuming you know what your JSON string is going to look like, you can use our RawMessageDataList and RawMessageDataObject to serialze your objects. This is pretty useful if you already are rendering JSON in an existing framework and don’t want to have to transform to and back again. The snippet below shows with static strings just so that you get the idea:

1
2
3
4
5
6
7
8
9
IMessageDataList people = new RawMessageDataList(
"[{'name':'joe','age':22},{'name':'jane','age':33}]");
 
IMessageDataList dog = new RawMessageDataObject("{'breed':'doberman','weight':78}");
 
Message message = new Message();
message.setData(new JSONMessageDataObject());
message.getData().put("people", people);
message.getData().put("dog", dog);

Using Coarse Grained objects

This is probably the simplest/prettiest way to implement your services assuming that you aren’t interested in using fine grained classes that are associated with most of today’s persistence frameworks. Here is how you would create a single compound JSON object:

1
2
3
4
5
IMessageDataObject dog = MessageUtils.createMessageDataObject();
obj.put("breed","doberman");
obj.put("wieght",78);Message message = new Message();
message.setData(new JSONMessageDataObject());
message.getData().put("dog", dog);

and now with a collection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
IMessageDataList&lt;IMessageDataObject&gt; people =
MessageUtils.createMessageDataObjectList();
 
IMessageDataObject joe = MessageUtils.createMessageDataObject();
joe.put("name","joe");
joe.put("age",22);
 
IMessageDataObject jane = MessageUtils.createMessageDataObject();
joe.put("name","jane");
joe.put("age",33);
 
people.put(joe);
people.put(jane);
 
Message message = new Message();
message.setData(new JSONMessageDataObject());
message.getData().put("people", people);

Summary

As you can see there are quite a bit of alternatives for you based on what your needs are to accommodate your service implementations. I’ve personally used all of the above as I’ve implemented:

  • Model Objects: using hibernate for persistence
  • Custom Serialization: for integrating with pre-rendered objects (commons-monitoring)
  • Coarse Grained: in implementing a dashboard/event driven solution

cheers and enjoy,

-andrew

cross-posted @ http://zuerchtech.com/2008/2/8/json-serialization-with-appcelerator-java-services

Technorati Tags: , , ,

Categories: announcements Tags: , , ,