Sunday, September 21, 2008

Using PyAMF and SQLAlchemy together

This past week I recieved the go-ahead to re-code the backend of our LIMS application with Python (it's currently PHP). It's not a minute too late, as I don't think I can stand typing another '->' or '$' without throwing something at the wall. I could go on about why I'm really sick of PHP and why Python rocks, but I'm sure you can read all about that elsewhere.

We'll be using Python's SQLAlchemy ORM, which kicks some serious ass. SQLAlchemy makes it amazingly simple to model complex relationships like inheritance hierarchies and many-to-many relationships that I could only implement with gobs of gnarly custom code in PHP.

Since we're already re-writing the backend we decided that we may as well tweak the Flex client at the same time. We are going to be making the switch from JSON to AMF for server-client communication, which will be more performant and allow us to transfer richer objects back and forth.

Python is pretty awesome for web-development, but the project that aims to support AMF (PyAmf) is still new and immature (but it does encode and decode as advertised and is under active development). In fact, the current stable release of PyAmf will not properly encode objects that are being managed by SQLAlchemy. There is a SQLAlchemy 'adapter' in the development branch of the PyAmf project that can be used, but I found the code to be lacking.

I decided to take matters into my own hands, and I am currently working on my own SQLAlchemy adapter that will hopefully work a little better. The code for my SQLAlchemy adapter can be found on Google code. It is not production ready, but if you want to experiment with it (tested only with SA 0.5), you should be able to drop it in the 'adapters' directory of the PyAmf 4.* branch to use it.

The adapter has 2 main features. It overrides the pyamf.util.get_attrs function so that the pyamf encoder skips any attributes of an object that are used by SQLAlchemy (_sa_instance_state, _sa_manager, etc), and it also identifies and translates SQLAlchemy collection objects, such as InstrumentedList objects.

Monday, August 25, 2008

Flex JSON-RPC implementation

So, you're checking out Flex and you're thinking to yourself, "Gee this e4x stuff is pretty rad, but it's 2008 and I could really use a good JSON implementation so I can integrate my bitchin' Flex component into my AJAX page." Amazingly, I was thinking the same thing, so I put together a couple of classes to implement a JSON-RPC v1.1 client.

The application code for this post is available on Google code. In addition to the JSON-RPC classes, the application contains a simple gui with controls for testing and logging JSON-RPC communication. To compile the code, you'll also need as3corelib in your compile path, which handles the JSON serialization/deserialization.

The 1st thing you'll need is a JSON-RPC server. If you don't already have one, it shouldn't be too difficult to put together. Follow this tutorial to create a simple Python JSON-RPC server, or use any 1.1 compliant server.

Next, we need to extend mx.rpc.AbstractOperation. This class will send the method invokation to the server and decode the result. Two important methods are overriden. The first is 'send', which will encode the request according to the JSON-RPC v1.1 spec, create a HTTPRequestMessage, and then call the parent invoke() to send the message to the server. If JSON encoding fails, a FaultEvent must be dispatched. Use the parent method dispatchRpcEvent() to make sure the event is dispatched by both the service and the operation.

The other important method is 'processResult', which decodes the response from the server and checks for any errors defined by the server application. The 'processResult' method is in the mx_internal namespace. If you're not familiar with using mx_internal, you should probably read up on it. The parent class takes care of most of the heavy lifting, but you will need to dispatch a FaultEvent if the JSON decode fails, or if a server application error was defined. Set the _result variable equal to the decoded result, and you're good to go.

Finally, we need to extend mx.rpc.AbstractService. This class is used to instantiate mx.rpc.AbstractOperation instances and invoke remote method calls in our application code. The class's main purpose is to act as a proxy that intercepts method calls, so we will be able to invoke a remote method with the syntax: service.method(arguments) instead of operation.send(method, args). You will need to override the 'getOperation' method to instantiate the correct mx.rpc.AbstractOperation subclass.

Here's how the jsonrpc.JsonRpcService can be used in your application code to communicate with the server:

import mx.rpc.events.*;

import jsonrpc.JsonRpcService;

private function callFoo(fooArgs:Object):void
{
// Create service object and
// call remote method 'foo'.
var jsonService:JsonRpcService = new JsonRpcService();
jsonService.rootUrl = 'http://localhost';
jsonService.url = 'test';
jsonService.addEventListener(ResultEvent.RESULT, gotBar);
jsonService.foo(fooArgs);
}

private function gotBar(event:ResultEvent):void
{
event.target.removeEventListener(ResultEvent.RESULT, gotBar);
var bar:Object = ResultEvent.result;
// do something with bar
}

Saturday, August 23, 2008

Flex360

We've been using Adobe Flex for the past 6-months to develop SLiM, our RIA client to access our backend GAPSS LIMS server. Flex is the perfect fit for LIMS, because we can do really cool stuff, such as performant drag and drop plate maps right in the browser.

I got my first chance to interact with the larger Flex community this past week at Flex360 in San Jose. I was half-expecting to meet a gaggle of converted Flash developers of the 'creative' type, but I was pleasantly surprised by the number of attendees using Flex for enterprise level applications. Many big companies are developing internal apps with Flex, and most of the community seemed to be very high quality.

Overall, the conference re-enforced the decision to use Flex for our app. I learned a ton of new technical info at the sessions and I'm trying to prioritize what was coolest, so I can go back and re-code sections of SLiM to be better.

Lims Coder

I'm starting this blog to discuss my experiences with the development of web-based LIMS. I'm drawing most of my content from experience developing applications for a university biotechnology core facility.

The topics will include server-side design, client-side design, lab equipment issues, code examples, and anything generally related to web-application development for life-sciences laboratories.