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.

August 14, 2008

Flex and GAE demo is online

Filed under: Software Development — Fernando Correia @ 9:29 pm
Tags: , ,

The demo application I’ve been working on is now online. It is an example of how to build a Flex client to a service running on Google App Engine. So it uses a RIA front-end and a cloud-based back-end.

You can reach the sample application at 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.

The source code is published on github and explained in several articles in my blog.

Feedback is welcome.

Mate Flex Framework

Filed under: Software Development — Fernando Correia @ 7:59 pm
Tags: ,

Brendan Campbell was kind enough to tell me about the Mate Flex Framework.

It seems to be more free-form than PureMVC, to demand less boilerplate code and to make a greater use of Flex concepts like events and tags.

Having just tried two frameworks (Cairngorm and PureMVC), I will not look into Mate right away. But I plan to do it eventually.

Some reviews are very positive:

August 13, 2008

Flex with GAE: adding participants to projects

Filed under: Software Development — Fernando Correia @ 9:45 pm
Tags: , ,

I’m making progress on my endeavor to build a Flex client to a Python service hosted on Google App Engine.

On the last iteration I had the whole architecture set up, using PureMVC on the client side and PyAMF on the service side. The application was able to show, create, edit and delete projects. It also handled project participants, but only in memory, without persisting them.

Now, the project participants are being persisted as Google App Engine model objects, referencing the project model objects.

This is the model definition on the server side:


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)

The service operations are implemented using a standard PyAMF RPC pattern (not REST yet):


class ProjectParticipantsService:
    def get(self, key):
        logging.debug('get %s' % (key))
        return self.to_dto(ProjectParticipant.get(key))

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

I am using the anonymous DTO approach that I described in a previous article:


def to_dto(self, participant):
    if participant is None: return None
    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

On the client side I have a domain object representing a project participant:


[Bindable]
public class Participant
{
    public var _key:String;
    public var projectKey:String;
    public var name:String;
    public var created_at:Date;
    public var modified_at:Date;

    public static function fromDto(dto:Object = null):Participant
    {
        var participant:Participant = new Participant();
        participant._key = dto._key;
        participant.projectKey = dto.project_key;
        participant.name = dto.name;
        participant.created_at = dto.created_at;
        participant.modified_at = dto.modified_at;
        return participant;
    }

    public function toDto():Object
    {
        var dto:Object = new Object();
        dto._key = _key;
        dto.project_key = projectKey;
        dto.name = name;
        dto.modified_at = modified_at;
        return dto;
    }

    public function toString():String
    {
        return name;
    }
}

I also follow PureMVC’s approach of using proxy objects to manipulate the model objects, like this:


public class ParticipantsProxy extends Proxy
    {
        public function getProjectParticipants(projectKey:String):ArrayCollection
        {
            if (participants[projectKey] == undefined)
               participants[projectKey] = new ArrayCollection;
            return participants[projectKey] as ArrayCollection;
        }

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

        private function onAddParticipantResult(result:Object):void
        {
            var participant:Participant = Participant.fromDto(result);
            var projectParticipants:ArrayCollection = getProjectParticipants(participant.projectKey);
            projectParticipants.addItem(participant);
            sendNotification(ApplicationFacade.PARTICIPANT_ADDED, participant);
        }

        // (etc.)
    }

The rest is done on the View layer, like this:


private function onAddParticipant(event:Event):void
{
    var newParticipant:Participant = new Participant();
    newParticipant.projectKey = participantsPanel.project._key;
    newParticipant.name = StringUtil.trim(participantsPanel.newParticipant.text);
    participantsProxy.addParticipant(newParticipant);
    participantsPanel.newParticipant.text = "";
}

You can download and browse the source code through github. Feedback is welcome.

July 30, 2008

Flex client using PureMVC

Filed under: Software Development — Fernando Correia @ 8:42 pm
Tags: ,

Continuing my quest to build a Flex client to a Python service on Google App Engine, I decided to try converting my previous example from the Cairngorm framework to PureMVC.

I liked the PureMVC approach better. Its notification mechanism is very simple and powerful. The view components are quite independent from the rest of the application. And, best of all, the framework’s architect, Cliff Hall, has a clear vision that the framework must be kept simple, with few features. He also is very active on writing documentation, examples and answering user questions on the forums.

After reading all documentation and examples I could find, I set out to convert one of those examples to deal with my business entitites: projects.

I must warn that what I am showing here is an exploratory project and a work in progress. It doesn’t represent, by any stretch, the best practices. By documenting my journey I intend to help others that may follow, and also to get some feedback and help on better approaches.

This is what the application looks like:

Using PureMVC the application is structured around a Façade object that has a reference to a collection of Models, a collection of Views and a collection of Controllers. Like this:

The model uses a “proxy” class that has the responsability of managing model objects. The view uses “mediator” classes that have the responsability of connecting the view to the application without too much coupling. And the controller has commands that are invoked by the framework when certain notifications are raised.

It is a good architecture with low coupling, high cohesion and clear separation of responsabilities. It is also lightweight and more concerned on providing guidance and structure than on restricting what the programmer can do. Currently I am considering this my framework of choice for my Flex experiments.

My post is not about explaining how PureMVC works. The project website does it quite well already, at least for those who are willing to invest a few hours learning it. But I will show some snippets of code that may at least raise some curiosity:

This is how the projects list forwards the “New project” command:

private function onNew(event:Event):void
{
    var project:ProjectVO = new ProjectVO();
    sendNotification(ApplicationFacade.NEW_PROJECT, project);
}

This is how the project form prepares itself for entering a new project:

case ApplicationFacade.NEW_PROJECT:
    projectForm.project = note.getBody() as ProjectVO;
    projectForm.mode = ProjectForm.MODE_ADD;
    projectForm.code.setFocus();
    break;

When the user submits the new project, this is how the project form handles this event:

private function onAdd(event:Event):void
{
    var project:ProjectVO = projectForm.project;
    projectProxy.addItem(project);
    sendNotification(ApplicationFacade.PROJECT_ADDED, project);
    clearForm();
}

So, the view mediator, that is a kind of Supervising Controller, causes the model to update itself with the new project’s data. This method in the model’s proxy class is implemented like this:

public function addItem(item:Object):void
{
    Gateway().call("ProjectService.save", new Responder(onAddItemResult), item);
}

So, it talks directly to the service using a remote object gateway.

There is also a Participants list, but it is not persisted to the server yet. It is only kept in the client’s memory and goes away when the application is closed. I am still trying to figure out the better way of dealing with it.

I hope this helps. The project is published on github. Feedback is welcome.

July 25, 2008

A few explanations about my test project

Filed under: Software Development — Fernando Correia @ 8:15 am
Tags: , ,

I thank Rien for giving valuable feedback on my test project. He had some questions that show I am not explaining my approach well enough. So I will try to clarify. Let see:

Love your idea of starting a good commented pytthon-flex-cairngorm project! Very much needed indeed!

Glad to hear you think that too. I think that as we share what we learn, all of us will benefit. One thing, though: this project is about a Flex client to Google App Engine. Not necessarily about Cairngorm. I will probably go the way of PureMVC. No problem for Cairngorm users, anyway, because the project is about the client-server integration, not about the framework for the Flex client.

I got your project running, there’s only one thing I do not understand just yet.

You have 2 folders “server” and “python-client”. They contain each pyamf in its whole? Is that necsessary?
It would help me and others much if you could explain why they are splitup in 2 seperate folders.

I agree that is a waste. Space is cheap, though. My reasoning is that I want my “server” directory to contain only what must be running at Google App Engine. No client tools at all. That is, I want a self-contained web service on GAE, and nothing else.

Since I also wanted a Python client to be able to test PyAMF in a way that is independent of Flex, that led me to create a “python-client” directory. I put a separate copy of PyAMF there so both subprojects (Python server and client) would be independent and self-contained, with no external dependencies.

And how the client.py knows of ProjectService.py and EchoService.py I don’t seem to get how they are linked up?

Well, first about the server. It does not know about any client. It only knows about requests that come through PyAMF.

About the clients, both (Python and Flex) are bound to the server in a naïve way that is suitable only for a test project. They use a fixed URL to the server (http://localhost:8080/) and they use the name of two services (EchoService and ProjectService) that are routed inside main.py in the server to the actual implementation classes.

Because I only start up “dev_appserver.py server”? And then openup the flex app.

You can start only one instance of the server on port 8080 and have both the Python and the Flex client talking to it.

I hope that clarifies a bit. Feel free to ask if you have more questions. Just keep in mind that I am still learning all this.

Good luck!

July 23, 2008

Cairngorm Flex client talking to Google App Engine

Filed under: Software Development — Fernando Correia @ 8:23 pm
Tags: ,

As I move forward in my project to learn about Flex and Google App Engine, I converted it to use the Cairngorm Flex framework.

My previous iteration was monolitic. Presentation, business and data access concerns where all mixed in a single source file.

This technique served my purpose to be able to see all my program in a single glance while I tried to learn how Flex worked. But this approach doesn’t scale for larger projects.

So I obviosly needed to learn how to get a better organization of a data-driven Flex application. Cairngorm was an obvious choice because it is supported and promoted by Adobe. They are even so kind as to send me periodic e-mails with tips about it!

So, I read Adobe’s introductory paper (Flex 3: Introducing Cairngorm, June 2008) and used the flex_ror_sdk_issue_tracker2 from the Ruby on Rails RIA SDK by Adobe project as an example.

In a few hours I had my application in a new structure. I even learned how to separate interface components in views, like this one:

User gestures are announced as events:


private function DeleteSelectedProjectClicked():void {
    var event:DeleteProjectEvent = new DeleteProjectEvent(dgProjects.selectedItem);
    event.dispatch();
    getProjects();
}

Such events are processed by commands like this:


public class DeleteProjectCommand implements ICommand
{
    private var __model:ModelLocator = ModelLocator.getInstance();
    private var __locator:ServiceLocator = ServiceLocator.getInstance();

    public function execute(event:CairngormEvent):void
    {
        var project:Object = (event as DeleteProjectEvent).project;
        var service:Services = __locator as Services;
        service.gateway.call("ProjectService.delete", new Responder(onResults), project);
    }

    public function onResults(result:Object):void {
    }
}

I can see that Cairngorm is a viable alternative to build Flex applications, specially larger ones. But there are some aspects of it that seem a bit odd to me. For instance, the idea of using a big bucket of global vars as your repository for model data. And also the way I have to repeat myself creating events and commands in paralel, and having to remember to include them in the controller.

My next step will be to experiment with the PureMVC framework, an alternative to Cairngorm.

My sample project is hosted on github. It is able to show, create, update and delete projects using a service written in Python and hosted on Google App Engine. The Flex client uses the Cairngorm framework and the Python service uses the PyAMF library for communication with the client.

Please be advised that this is a learning project and does not represent a production-quality application or an example of best practices.

Feedback is welcome.

Edit: This is an ongoing project that has advanced quite a lot since this article. Browse my blog if you’re interested in learning about the progress of this example.

July 19, 2008

Flex client updating objects in Google App Engine

Filed under: Software Development — Fernando Correia @ 10:31 pm
Tags: , ,

I am continuing to learn how to integrate Flex to Google App Engine. Now my test project is able to update objects, in addition to inserting and retrieving them.

On the server side, this is done by the update service operation:

def update(self, project):
    logging.debug('udpate %s' % (project))
    existing_project = Project.get(project._key)
    existing_project.name = project.name
    existing_project.put()
    return Project.get(project._key)

There is also a new save operation that decides between insert and update depending on the state of the object. If the object was read before, it is updated. Otherwise, it is inserted:

def save(self, project):
    logging.debug('save %s' % (project))
    if hasattr(project, '_key') and project._key != None:
        return self.update(project)
    else:
        return self.insert(project)

The App Engine model is also saving the date and time each object was last modified:

class Project(db.Model):
    # ...
    modified_at = db.DateTimeProperty(auto_now=True)

On the client side, the save operation is called after an object is prepared. If the object was being edited, its key was saved and so the service will know it must be updated. If it is a new object, the key will be null so the service will insert a new object.

public function submitProject():void {
    var newProject:Object = new Object();
    newProject.code = project_code.text;
    newProject.name = project_name.text;
    newProject._key = project._key;
    gateway.call("ProjectService.save", new Responder(null, onFault), newProject);
    getProjects();
}

The _key property is a very important piece of information in this context. So I patched the PyAMF library to include it within every object it sends to the client. There is a ticket for that on the PyAMF project.

def writeObjectAMF(self, obj, args, kwargs, remove):
    """
    Writes an object that has already been prepared by writeObjectAMF0 or writeObjectAMF3.
    """
    try:
        obj._key = str(obj.key())
    except:
        obj._key = None
    self.writeObject(obj, *args, **kwargs)
    del obj._key
    if remove:
        self.context.class_aliases[obj.__class__] = None

All the source code for this project is hosted in github. Please be aware that I am sharing what I find out as I learn. I am sure there are better ways of using this tools. I hope to learn them. Comments are welcome.

July 18, 2008

Debugging Flex apps with Firefox

Filed under: Software Development — Fernando Correia @ 9:23 am
Tags:

While I was building my Flex client to a Google App Engine application, I was not able to make the Flex 3 debugger work.

I found out that this is a known bug related to Firefox 3. There is a workaround of setting the wmode parameter to “opaque” in index.template.html, but that didn’t work for me.

What did work, though, was to set Flex 3 to use another browser. This is done by opening the Window | Preferences dialog and adding a new browser in the General | Web Browser section.

I was able to debug using Internet Explorer. Later I installed Safari and it worked too. It seems to open faster than IE, so I’ll probably use it to debug my Flex apps until the issue with Firefox 3 is sorted out.

July 17, 2008

Flex client talking to GAE

Filed under: Software Development — Fernando Correia @ 10:29 pm
Tags: ,

In a new iteration of my Flex and Python Test project, I created a crude Flex client. It is able to talk to the GAE server using AMF and perform two operations: retrieve all projects, and insert a new project. Both the client and the server see the data as objects.

This is what the user interface looks like:

And this is the Flex source code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="onInit()">
    <mx:Script>
       <![CDATA[
        import flash.net.Responder;
        import mx.controls.Alert;

           [Bindable]
        public var dataProvider:Array;

        [Bindable]
        public var statusMsg:String;

        public var gateway:NetConnection;

        public function onInit():void
           {
            statusMsg = "Loading data...";
               gateway = new NetConnection();
               gateway.connect("http://localhost:8080/");
            getProjects();
          }

        public function getProjects():void {
            gateway.call("ProjectService.get_all", new Responder(getResult, onFault));
        }

        public function getResult(result:Array):void {
            dataProvider = result;
            statusMsg = "Data loaded.";
        }

        public function submitProject():void {
            var newProject:Object = new Object();
            newProject.code = project_code.text;
            newProject.name = project_name.text;
            gateway.call("ProjectService.insert", new Responder(null, onFault), newProject);
            getProjects();
        }

        public function onFault(info:Object):void {
            statusMsg = info.toString();
        }
       ]]>
    </mx:Script>

    <mx:DataGrid id="dgProjects" x="10" y="10" dataProvider="{dataProvider}"
        width="356" height="183">
        <mx:columns>
            <mx:DataGridColumn headerText="Code" dataField="code"/>
            <mx:DataGridColumn headerText="Name" dataField="name"/>
        </mx:columns>
    </mx:DataGrid>
    <mx:Button x="374" y="11" label="Reload" click="onInit()"/>
    <mx:Label x="10" y="203" text="Created at"/>

    <mx:TextInput x="103" y="201" id="selected_created_at"
        text="{dgProjects.selectedItem.created_at}" width="263"/>
    <mx:Form x="10" y="240" width="356" borderStyle="solid" cornerRadius="2">
      <mx:FormHeading label="New Project"/>
      <mx:HBox>
         <mx:Label text="Code"/>
         <mx:TextInput id="project_code" width="159"/>
      </mx:HBox>
      <mx:HBox>
         <mx:Label text="Name"/>
         <mx:TextInput id="project_name"/>
      </mx:HBox>
      <mx:Button label="Insert" click="submitProject()"/>
    </mx:Form>
    <mx:Label x="10" y="384" text="{statusMsg}" width="356"/>
</mx:Application>

The project is hosted in github. Feedback is welcome.

Next Page »

The Rubric Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.