Dec 7
Introducing Metro - A Transfer ORM Service Factory and More...
Metro , Transfer , Ideas , ColdFusion , ColdSpring Add comments
Metro is a library of components to support rapid development of applications that use ColdSpring and Transfer ORM.
Impetus
While developing projects with Transfer over the course of the past year, I've noticed a repetition in the application model code that led me to adopt some basic conventions thereby actively generating much of the code I would have created with passive code generation. Convention based code generation will only get you so far, there are nuances to an application model that are difficult to achieve with code generation. To hedge this, Metro makes it easy to define concrete components (services or gateways) that extend the core Metro components, so one can write custom code to override and/or augment the actively generated code.Conventions
The over-reaching convention for metro is the concept of packaging related object so that they are managed by a single service. As an example, Metro includes a security package with simple User, Role and Permission objects that are managed by a single SecurityService composed with a gateway for each object. To achieve this, Metro parses the transfer XML configuration into a simplified config structure.API
A service created by the Metro ServiceFactory provides get(), new(), list(), save() and delete() methods for objects under a given package. For example, the security package included in metro contains three objects: User, Role and Permission. One can use get("objectName") or get{objectName}(), etc. for each object managed by the service. The syntactic sugar of get{objectName}() is achieved through onMissingMethod.Setup
Metro is setup using ColdSpring and Transfer. Below is a sample bean definitions configuration included in the tests folder.<beans>
<bean id="TransferConfig" class="transfer.com.config.Configuration">
<constructor-arg name="datasourcePath"><value>${datasourcePath}</value></constructor-arg>
<constructor-arg name="configPath"><value>${transferConfigPath}</value></constructor-arg>
<constructor-arg name="definitionPath"><value>${definitionsPath}</value></constructor-arg>
</bean>
<bean id="TransferFactory" class="transfer.TransferFactory">
<constructor-arg name="configuration"><ref bean="transferConfig"></ref></constructor-arg>
</bean>
<bean id="datasource" factory-bean="TransferFactory" factory-method="getDatasource" />
<bean id="transfer" factory-bean="TransferFactory" factory-method="getTransfer" />
<bean id="transaction" factory-bean="TransferFactory" factory-method="getTransaction" />
<bean id="TransientFactory" class="metro.factory.TransientFactory" singleton="true">
<constructor-arg name="classes">
<map>
<entry key="Result">
<value>metro.util.Result</value>
</entry>
<entry key="Timer">
<value>metro.util.Timer</value>
</entry>
</map>
</constructor-arg>
<constructor-arg name="afterCreateMethod">
<value>setup</value>
</constructor-arg>
<property name="beanInjector">
<ref bean="beanInjector" />
</property>
</bean>
<bean id="ServiceFactory" class="metro.factory.ServiceFactory" lazy-init="false">
<constructor-arg name="TransferFactory">
<ref bean="TransferFactory" />
</constructor-arg>
<constructor-arg name="TransferConfig">
<ref bean="TransferConfig" />
</constructor-arg>
<constructor-arg name="TransientFactory">
<ref bean="TransientFactory" />
</constructor-arg>
<constructor-arg name="componentPath">
<value>model</value>
</constructor-arg>
</bean>
<bean id="SecurityService" factory-bean="ServiceFactory" factory-method="getService">
<constructor-arg name="packageName"><value>security</value></constructor-arg>
</bean>
<bean id="Validator" class="metro.core.Validator" />
<bean id="beanInjector" class="metro.lib.BeanInjector" />
<bean id="TDOBeanInjectorObserver" class="metro.lib.TDOBeanInjectorObserver" lazy-init="false">
<constructor-arg name="transfer">
<ref bean="transfer" />
</constructor-arg>
<constructor-arg name="debugMode">
<value>true</value>
</constructor-arg>
<property name="beanInjector">
<ref bean="beanInjector" />
</property>
</bean>
</beans>
In this example, I set up Transfer using the configuration object and several other objects that are included in the library. Once configured, one can create a Singleton instance of a service by calling the
getService() factory method and passing the package name as a constructor argument.
The Metro ServiceFactory accepts 4 constructor arguments, the TransferFactory, TransferConfig, TransientFactory (another factory included in the library), and the component path, which is the relative path to your packaged model components. The ServiceFactory will check if any components exist in the package under the specified component path and will return an instance of the concrete class instead of the core class. Concrete components must extend either "metro.core.Service" or "metro.core.Gateway" in order for the ServiceFactory to understand which component to create. Additionally, Gateways must provide an additional metadata in the form of a component attribute "objectName".
<cfcomponent displayname="UserGateway" objectName="User" extends="metro.core.Gateway" output="false">
The security package included in metro provides an example of a concrete Service and Gateway.
Dec 8, 2008 at 6:51 PM Awesome!
Have you considered doing a online coldfusion meetup to introduce Metro to us? I think the CF community would really appreciate it if you can answer the question "What's Metro?" and "Why use Metro?" during a visual presentation.
The Online ColdFusion Meetup
http://www.meetup.com/coldfusionmeetup/
Dec 8, 2008 at 8:04 PM Thanks, Henry!
I will give a presentation some thought. I'm hoping to write up some tutorials and documentation first...
Cheers!
Dec 9, 2008 at 10:45 AM This is great. I have been pouring over Bob Silverberg's series on transfer trying to get my head around how to use his populate method to make Transfer more code generator friendly. This seems to be just what I was looking for.
It would be great if you would provide an example that does not use unit tests for those of us not familiar with unit testing.
Thank you for your contribution.
Jan 6, 2009 at 12:13 PM Hey, fancybread. This should be in the Metro category.
Jan 6, 2009 at 12:56 PM Heh, it is now...