Sunday, February 12, 2006

Introducing auto-magic Remoting with ColdSpring

This is kind of a mix between some features that have been available in the ColdSpring BER and some new additions to the AOP framework. Not only is this a kick ass new feature, but it’s also a collaborative effort of Kurt, Dave, and myself, with lots of input from Paul Kenney and Sean Corfield. So kudos goes out to everyone involved! Here’s a general overview of what auto-magic remoting means. Let’s say you have a service component registered with ColdSpring, which does some database access for some piece of a web app. What if we want to take a few of the methods of that service and make them available as remote methods for a flex app, or a web service. Wouldn’t it be nice to simply add a component to the ColdSpring config file that has a list of methods you would like to expose, that will automatically configure itself to your service component, expose those methods as remote, taking care of the CFC to AS object translation for you? How about if you could also simply plug in a security through AOP as well, and pretty much write no additional code at all. Well, that’s exactly what ColdSpring Remoting is all about! So let’s see how we can do this in practice. We’ll start simply, with the configuration of a remote facade, or proxy (it’s sort of a little of both) for a service component, then we’ll add the CFC to AS object translation and finish up with some security. Here’s our service, it’s from the klondike records application available in the BER, in the examples folder.

<!-- catalog service -->
<bean id="catalogService" class="net.klondike.component.CatalogService">
    <property name="catalogDAO">
        <ref bean="catalogDAO" />
    </property>
    <property name="catalogGateway">
        <ref bean="catalogGateway" />
    </property>
</bean>


I won’t go into the code for the components, but this service has methods for listing, searching, adding and updating records (as in vinyl, not tables). I would like to create a remote façade to expose the ‘list’ methods, which would be any methods starting with ‘get’. So I’ll configure a RemoteFactoryBean which creates a proxy, writes it to disk at a specified location (so that the ColdFusion flashGateway can find it) and I’ll tell it which methods to include, which will have ‘remote’ access. Here’s the config:

<!-- a remote service bean -->
<bean id="remoteCatalogService" class="coldspring.aop.framework.RemoteFactoryBean">
    <property name="target">
        <ref bean="catalogService" />
    </property>
    <property name="serviceName">
        <value>RemoteCatalogService</value>
    </property>
    <property name="absolutePath">
        <value>/usr/local/cf7/htdocs/klondike/machii/remoting/</value>
    </property>
    <property name="remoteMethodNames">
        <value>get*</value>
    </property>
</bean>


I set the target to the service cfc I already configured, I give this remote service a name and an absolute path (I could also have used the property ‘relativePath’, meaning webroot relative) where I want the RemoteFactoryBean to create the service, and I give it a pattern to match methods on, so in this case all methods that begin with ‘get’ are included as remote methods. That’s it! When ColdSpring starts up, I can ask it to create the service (I’ll get into that part later) and I’m done! No code written at all! This new remote service will now be available at www.yourdomain.com/klondike/machii/remoting/RemoteCatalogService, ready to go. Pretty slick, huh?

OK, so a few things to point out before I move on. We are using AOP under the hood, so what you are creating is very similar to a proxy object, and it uses the same mechanism for method interception. So what does that mean? Well for one thing, adding translation to and from AS objects to CFCs is a matter of adding a type of around advice configured specifically for remoting. Of course this component is provided by ColdSpring, and the RemoteFactoryBean knows how to configure it for you, all you have to do is properly configure a flashUtilityService and give it to the RemoteFactoryBean. Here’s how we set that up:

<!-- A ColdSpring provided component that inconjunction with flashUtilityService can map ActionScript objects to CFCs. -->
<bean id="flashMappings" class="coldspring.remoting.flash.flashMappings">
    <constructor-arg name="mappings">
    <!-- Here we use a "list" element to pass in an array of structures to the constructor -->
    <list>
        <map>
            <entry key="cfcType">
                <value>net.klondike.component.Record</value>
            </entry>
            <entry key="asType">
                <value>RecordVO</value
            </entry>
        </map>
    </list>
    </constructor-arg>
</bean>

<!-- A service object which can be used by a remote facade to convert CFCs to ActionScript classes and visa versa -->
<bean id="flashUtilityService" class="coldspring.remoting.flash.flashUtilityService">
    <property name="flashMappings">
        <ref bean="flashMappings"/>
    </property>
</bean>


I’ve defined a ColdSpring flashMappings object with the cfcType and asType to translate between. You provide a list of mappings, each one is defined as a map with a key for the CFC and AS types to translate between. Next I simply define the flashUtilityService and provide the mappings object. So now I just give this service to the RemoteProxyBean defined above. Now the config will look like this, all I have added is the property ‘flashUtilityService’:

<bean id="remoteCatalogService" class="coldspring.aop.framework.RemoteFactoryBean">
    <property name="target">
        <ref bean="catalogService" />
    </property>
    <property name="serviceName">
        <value>RemoteCatalogService</value>
    </property>
    <property name="absolutePath">
        <value>/usr/local/cf7/htdocs/klondike/machii/remoting/</value>
    </property>
    <!-- add the new flashUtilityService -->
    <property name="flashUtilityService">
        <ref bean="flashUtilityService" />
    </property>
    <property name="remoteMethodNames">
        <value>get*</value>
    </property>
</bean>


Now my remote service will do all the translation between AS objects and CFCs for me, viola! So what if I want to add a little security to this service, or some logging? As I said before, we are using AOP; RemoteProxyBean actually extends ProxyFactoryBean, and can be configured with any method interceptors or advisors as well. So adding logging and security is pretty much a breeze. I’m not going to go through setting up those advisors, you can read over my first and second AOP tutorials, but here’s how I add them to the remote service:

<bean id="remoteCatalogService" class="coldspring.aop.framework.RemoteFactoryBean">
    <property name="target">
        <ref bean="catalogService" />
    </property>
    <property name="serviceName">
        <value>RemoteCatalogService</value>
    </property>
    <property name="absolutePath">
        <value>/usr/local/cf7/htdocs/klondike/machii/remoting/</value>
    </property>
    <property name="flashUtilityService">
        <ref bean="flashUtilityService" />
    </property>
    <!-- add the logging and security advisors --
    <property name="interceptorNames">
        <list>
        <value>loggingAdvisor</value>
        <value>securityAdvisor</value>
        </list>
    </property>
    <property name="remoteMethodNames">
        <value>get*</value>
    </property>
</bean>


There you go! I added the logging and security advisors in the same way as if I was setting up a normal AOP proxy bean, and that’s it. I now have a pretty sophisticated remote service, with type translation, logging and a security framework all built in, and I didn’t write a speck of code, all I did was rewire existing components from my application. Now that’s cool!

Now all that we need to do is ask ColdSpring to actually create the remote service. There’s a couple of ways you can do this. If you call getBean(‘remoteCatalogService’) on the factory, that will follow the same principles as when using any factory with ColdSpring, and create the service. However, the RemoteFactoryBean has some useful methods for managing remote services, so you may want to retrieve the factory itself from ColdSpring. You can do this by calling getBean(‘&remoteCatalogService’) on the bean factory. This will return an instance of the factory itself and you can then call factory.createRemoteProxy() to create the service, factory.destroyRemoteProxy() to remove it, and factory.isConstructed() to see if the service is ‘alive’. I have some creative uses of the RemoteProxyBean api that I’m looking forward to showing at cf.Objective, so I’ll see you there, and happy remoting!

1 Comments:

Anonymous Jared said...

Lookin good, there, dude! :)

7:39 AM  

Post a Comment

<< Home