Fernando Correia’s Weblog

August 23, 2008

Example of RIA in the cloud

Filed under: Software Development — Fernando Correia @ 12:34 pm
Tags: , , , , ,

When I decided to learn and get some first-hand experience about Rich Internet Applications (RIA) and distributed application hosting (cloud computing), I chose to do it using Flex and the Google App Engine. Flex is a mature tool that has a plethora of rich interface capabilities and is very good to connect to services on the Web. And the App Engine is a very intriguing proposition where you use Google’s infrastructure to run your application.

To share my experience and get some feedback I started a project called “Flex and Python Test”. Now this project is finished and released. The application is a very simple project portfolio that can keep a list of projects and participants. The data is kept on the client for fast response, and the modifications are sent to the server for persistence. This is what the application looks like:

The source code for this application is available on github. If you want to understand it, download it and browse the code. To help, I will explain a bit about the design.

This is the general architecture:

The client is a Flex application running in a browser. Flex allows us to have a rich interface without dealing with incompatibilities between browser implementations. The server is a Python application running in Google App Engine. The client send requests through HTTP using the AMF encoding format. This is a binary format that is very efficient for Flex applications. The server processes the requests and sends responses also encoded in AMF. The server exposes its interface in the Remote Procedure Call (RPC) pattern.

If you download the source, take a look at README.txt. It explains how to run and deploy the application. There are three directories: flex-client contains the Flex application that will run in the browser. python-client contains an alternate client in Python that you can run in your computer to initialize data, test the service and learn the API. server contains the Python service that is deployed to Google App Engine.

To build the Flex client I decided to use a Model-View-Controller (MVC) framework. A sound structure helps when you want to build larger applications. After experimenting with Cairngorm, I went for PureMVC. If I would make another iteration I might now try Mate.

With PureMVC, this is the overall architecture of my client application:

The Model represents the data. It uses the Proxy pattern to control access to the remote service. The View contains the user interface. It uses the Mediator pattern to implement Supervising Presenters that manage the interface components. The Controller contains business logic. It uses the Command pattern to execute actions that interact with several other components. The model, view and controller objects communicate using a Publish/subscribe-style Observer notification scheme.

For instance, this is how the Participants proxy asks the server to insert a new participant:


public function addParticipant(participant:Participant):void
{
    ServiceGateway.GetConnection().call("ProjectParticipantsService.save",
        new Responder(onAddParticipantResult, onFault), participant.toDto());
}

On the server side, Google App Engine takes care of executing your application when it receives requests. The Python application uses PyAMF to decode the client requests and execute the service operation that is being called. The data that is transferred between the client and the server is stored in Data Transfer Objects (DTOs). Since both Python and Actionscript are dynamic languages, I didn’t declare formal type structures for these DTOs. They are just dynamic objects. The service operations use App Engine’s Datastore API to store and retrieve objects.

This is how the ProjectParticipants service executes the operation to insert a new participant:

def save(self, participant_dto):
    if hasattr(participant_dto, '_key') and participant_dto._key != None:
        return self.update(participant_dto)
    else:
        return self.insert(participant_dto)

def insert(self, participant_dto):
    participant = ProjectParticipant()
    participant.project = Project.get(participant_dto.project_key)
    participant.name = participant_dto.name
    participant.put()
    return self.to_dto(participant)

Some of my previous posts have more details about how I built this application:

I’ve deployed this sample application to Google App Engine. You can interact with it using this URL:

http://fernando-correia.appspot.com/

Click on Edit projects to open the RIA client. If you refresh the homepage you should see the updates you made.

I hope this can help other people who want to learn some of these techniques and tools. Your feedback is most welcome.

Advertisements

August 2, 2008

Returning DTOs from PyAMF

Filed under: Software Development — Fernando Correia @ 12:14 pm
Tags: , ,

Serializing Google App Engine model objects using the AMF protocol is very efficient. AMF even supports references to objects, so repeated serialization of references to the same object won’t waste bandwidth.

For instance, if we have a model like this:

class Project(db.Model):
    code = db.IntegerProperty()
    name = db.StringProperty()
    department = db.IntegerProperty(default=0)
    created_at = db.DateTimeProperty(auto_now_add=True)
    modified_at = db.DateTimeProperty(auto_now=True)

class ProjectParticipant(db.Model):
    project = db.ReferenceProperty(Project, collection_name='participants')
    name = db.StringProperty()
    created_at = db.DateTimeProperty(auto_now_add=True)
    modified_at = db.DateTimeProperty(auto_now=True)

And we return a list of 5 participants of 2 projects, each project’s data could be serialized only once, although on the client side we will have the project data in each participant instance. This is good and PyAMF supports this feature. [Edited after some clarification from Nick Joyce.]

But sometimes we may want more control over what is serialized. For instance, we can have an object that has references to 5 other objects. But our client may not need to use their data, so it would be a waste to serialize it.

We can have fine control over what is serialized, with more work on the server side, by creating a data transfer object (DTO) that will be returned. That way we can decide whether we want deep or shallow serialization. We can also restrict the data that will be serialized and return keys or references as we think will be better for use on client side.

This is an example of the DTO approach:

class DTO(object):
    pass

class ProjectParticipantsService:
    def get(self, key):
        return self.to_dto(ProjectParticipant.get(key))

    def to_dto(self, participant):
        dto = DTO()
        dto._key = str(participant.key())
        dto._id = participant.key().id()
        dto.project_key = str(participant.project.key())
        dto.name = participant.name
        dto.created_at = participant.created_at
        dto.modified_at = participant.modified_at
        return dto

A generic DTO class is used. I don’t see much point on creating a specific class, like you would do on Java. This way, you only have one place where you control your DTO’s structure. DRY.

Some caveats that may bite you when you are coding late at night:

  • Your DTO cannot be a direct instance of object, like dto = object(). Instances of object cannot be extended with dynamic attributes.
  • Be sure to convert the key to a string. If you try to serialize the key itself, like dto.project_key = participant.project.key(), there will be an error like “AttributeError: ‘str’ object has no attribute ‘iteritems'”.

I published an example at github.

“At last! It works.” (Cosmix)

Blog at WordPress.com.