Annotation based Action classes
tfennelly Apr 21, 2010 12:09 PMWith subversion lockdown at the moment, I decided to have a look at how we could improve the Action class API... make it a bit easier to use.
So at the moment, to implement an Action you need to implement the ActionLifecycle interface (or one of it's derived interfaces/classes). Configuration is done through the universally hated ConfigTree, which must be supplied via constructor. In all... implementing an Action is quite ugly (imo).
After a few hours playing, I have the following working. You can implement an action that looks like the following:
public class Action1234 { @ConfigProperty private File pickupFile; @ProcessMethod public void processMethod(Message m) { FileWriter writer = new FileWriter(pickupFile); // etc.... } }
No need to implement interfaces... no ConfigTree... configuration is reflectively injected via the @ConfigProperty annotation on the bean fields/setters.
The esb config for this looks just like any other action:
<action name="action" class="com.acme.Action1234"> <property name="pickupFile" value="./pickupFile.xml" /> </action>
It also supports @ProcessMethod implementations that take non ESB Message parameters e.g.
public class Action1234 { @ProcessMethod public OrderAcknowledgment processOrder(Order purchaseOrder) { // Do your thing with the order... return new OrderAcknowledgment(....); } }
In the above case, the Order instance needs to be set as the ESB Message payload i.e. the action configured before this action needs to create the Order (via transformation etc) and set it as the payload on the Message instance it returns. This Order will then get extracted from the ESB Message and passed into the processOrder method. Likewise with the OrderAcknowledgement return val... set on the ESB Message instance forwarded to the next action in the pipeline. All this is done using the standard MessagePayloadProxy get/set mechanism. Would be easy enough (I think) to add marshal/unmarshal support here, for marshaling e.g. an XML message payload into java objects that can then be used as args to the @ProcessMethod - opposite on the way out.
Lifecycle... initialize and destroy... add public no-arg methods and annotate them with @Initialize or @Destory.
The @ConfigProperty annotation for injecting the config params was lifeted from Smooks (called @ConfigParam in Smooks). It handles extraction of the config parameter (form the ConfigTree) and injection into the bean. Also handles all the decoding e.g. in the case above, decoding the string value into a java.io.File instance. Handles REQUIRED and OPTIONAL config params... "choices" etc. This removes a lot of noise from the code!!
All of this was done within the confines of the current Actions, ConfigTree etc APIs. The bean action is wrapped in a normal ConfigTree/ActionLifecycle action implementation (I currently call it BeanContainerAction). It did require a relatively small addition to the ActionProcessingPipeline to hook in this new type of action, wrapping it in the BeanContainerAction.
The @ConfigParam an lifecycle annotations could also be used on the listeners etc... thereby hiding our beloved ConfigTree from most users