September 28, 2005
Some notes about using OpenAMF
We've been using OpenAMF to connect a Flex client to a Tomcat server in the current project I'm working on. I'm impressed with how well OpenAMF works, but there were a few gotchas we ran across when trying to set up and configure everything. Here are some things to keep in mind if you decide to use OpenAMF in your own projects.
We use the Value Object pattern in order to transfer data between client and server. Rather than call a remote method with different types of parameters, we'll package everything up into a Value Object and send the Value Object over the wire. This is especially handy because with OpenAMF we can map an ActionScript class to a Java class. If we send a PersonVO ( defined in Person.as ) as a method parameter, we can type that parameter as a PersonVO ( defined in Person.java ) on the server.
In order to accomplish this, there are two things you need to do:
- Create a mapping in the WEB-INF/openamf-config.xml file on the server
- Associate the string name to the class instance on the client
For #1, open up the config file and add a mapping like this somewhere in the config file under the config root element:
<custom-class-mapping> <java-class>com.whatever.vo.PersonVO</java-class> <custom-class>com.whatever.vo.PersonVO</custom-class> </custom-class-mapping>
For #2, we need to add an Object.registerClass() call on the client sometime during the application startup process:
Object.registerClass( "com.whatever.vo.PersonVO", com.whatever.vo.PersonVO );
The above is necessary to convert the ValueObjects received from the server into their native ActionScript 2 class equivalents.
The last item I wanted to mention is to be careful with your ValueObjects whenever you have complex types in them. For instance, if a PersonVO has a "books" array (of BookVO instances), it's very important that the books array is never initialized in the VO. That is, this code:
class PersonVO { public var books:Array; // of BookVO public function PersonVO() { books = new Array(); } }
... will cause problems when you get the data from the server. The constructor is called after all of the values are set, so you'll never get the right data from books because you're always overwriting it! Remember to keep your constructors in your ValueObjects empty or else you might overwrite data accidentally.
The reason we ran into the constructor issue was that we were creating some mock ValueObjects client side because the server code wasn't ready yet. In testing the client, instead of making an actual remote call we'd make a call that used setInterval to construct some VOs and pass them as parameters back, simulating the onResult method of Flash Remoting. Our VO constructors created new complex objects so that we could create our mock data easily. It was only when we switched from the mock calls to the real ones did we run into the issue, and boy was that fun to debug...
I hope this helps someone in the future using OpenAMF on their Flash / Flex projects!
Now, if only ColdFusion could map .cfc's to .as files as easily. I've used the _remoteClass trick in previous projects, but when you have VOs that contain arrays of other VOs that contain more VOs, it gets complex fast. We chose Java over ColdFusion simply because OpenAMF provided a more robust Flash Remoting solution, and made the client-server integration layer easier to write.

Comments
The funny thing about AMF deserialization is, that members are set on the object *before* the constructor function is called. One trick to overcome this issue is to add some logic to the VO's constructor function:
public function PersonVO() {
if (this.books == undefined) {
books = new Array();
}
}
This ensures that the Array will be created if you instantiate the class "by hand" but will get the deserialized books Array when received through AMF.
Btw, to pass typed objects between CF and Flex you can use "pseudo" VOs: create an instance of flashgateway.io.ASObject in the CFC, fill it with data and pass it over to Flex. CF will treat this object as a struct, e.g.
Dirk.
Posted by: Dirk Eismann at September 28, 2005 03:13 PM
Hmm, the CF code sample has been stripped off...
Posted by: Dirk Eismann at September 28, 2005 03:14 PM
Dirk, I'd love to see that snippit of CF code!
Leif
Posted by: Leif Wells at September 28, 2005 03:42 PM
Thanks for the replies Dirk. We ended up doing the same with our constructors when we found out that our VOs were being "corrupted" when received from the server by unconditional constructor logic in the client side class. Jesse had reported a similar problem here: http://www.jessewarden.com/archives/2005/04/class_deseriali.html
The ColdFusion snippet posted was this:
<!--- inside CFC --->
<cfset obj = createObject("Java", "flashgateway.io.ASObject").init()>
<cfset obj.setType("PersonVO")>
<cfset obj.put("books", ...)>
But even so, that's a workaround at best. I've love to see ColdFusion support mapping PersonVO.cfc with PersonVO.as. Perhaps in the next version...?
Posted by: darron at September 28, 2005 03:51 PM
Yeah! OpenAMF rocks! :)
We are creating a huge RIA with OpenAMF and the backend business logic relys mainly in EJBs. This solution combined with the AdvancedGateway makes the application performance awesome.
OpenAMF is a very robust Flash Remoting implementation, and I only miss some few things mainly:
1.- setCredentials are not implemented (or at least I couldn't find it ;))
2.- Someone says that pageable record sets don't work well (I don't know as I don't use it).
OpenAMF is a truly great project to deliver open source RIAs :)
Posted by: Carlos Rovira at September 29, 2005 04:02 AM
The problem with CFCs is that they're not really atomic entities as POJOs. A CFC is an abstraction of several CF runtime classes (e.g. every cffunction in a CFC becomes an instance of a CF runtime Java class). The only way would be to introduce a custom VO CFC type that gets converted into an ASObject on-the-fly and behind-the-scenes but this is basically the same as my workaround. Until MM does not provide a native CFCAdapter for the AMF Gateway (aka. Remoting gateway) there will only be workarounds...
Posted by: Dirk Eismann at September 29, 2005 08:39 AM
Sure thing about the constructors issue, finally got it solved as you said.
It was driving me mad...
Thanks a lot man!!
Cheers! =D
Posted by: Juan at September 30, 2005 11:48 PM
What does your ActionScript 2 connection code look like? Are you using Flex's RemoteObject tag or the Flash Remoting ActionScript libraries.
Alon
Posted by: Alon at October 18, 2005 05:02 PM
This maybe a silly question, but is there any cost to implementing Flash UI - Java backend application beside the purchasing of Flash MX IDE? So no need to purchase Flash MX remoting component because it's replaced by OpenAMF?
Thanks,
Peter
Posted by: Peter at November 21, 2005 06:14 PM
And can somebody help me - if I have a scheme:
FlashClient -> FCS <- Tomcat :: web-service :: <- Non-Flash CLient
Which technology should I choose to exchange text messages between to different client via the Flash Communication Service (FCS) as a gateway ?
Posted by: Alex at February 2, 2007 11:49 AM