Annotation based Action classesTom Fennelly Apr 21, 2010 12:09 PM
With 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
1. Re: Annotation based Action classesBurr Sutter Apr 21, 2010 1:08 PM (in response to Tom Fennelly)
A POJO Action (custom mediator) would be a HUGE improvement over the curent Action API. I am all for it. :-)
Another goal/benefit would be to improve automated Unit Testing (e.g. via JUnit or TestNG).
Please show a mock-up of the jboss-esb.xml in the case of the Order instead of the Message example - it helps to visualize these things.
2. Re: Annotation based Action classesDaniel Bevenius Apr 22, 2010 4:24 AM (in response to Burr Sutter)
This looks nice. I like!
/Dan
3. Re: Annotation based Action classesHans Wolffenbuttel Apr 23, 2010 8:40 AM (in response to Tom Fennelly)
Hi Tom,
Does this mean you could have more then one @ProcessMethod with differend parameters where the kind of payload will activate the right one for the job?
I will illustrate: Say you have differend kinds of orders: orders-send-by-mail, orders-picked-up-at-location and express-orders. All these orders are converted by unmarshalling it from XML to Java-objects. Then the actionclass would look like:
{code:java}HandleOrderAction{
public class
@ProcessMethod
public OrderAcknowledgment processOrder(MailOrder purchaseOrder){
// Do your thing with the order...
return new OrderAcknowledgment(....);
}
@ProcessMethod
public OrderAcknowledgment processOrder(PickupOrder purchaseOrder){
// Do your thing with the order...
return new OrderAcknowledgment(....);
}
@ProcessMethod
public OrderAcknowledgment processOrder(ExpressOrder purchaseOrder){
// Do your thing with the order...
return new OrderAcknowledgment(....);
}
}
{code}
So when an expressorder is placed, the processmethod will call the method with the ExpressOrder as incoming parameter, when a mailorder is placed the method will be called with the MailOrder parameter and so on.
Will this work or is this possible in any way?
regards,
Hans
4. Re: Annotation based Action classesTom Fennelly Apr 24, 2010 4:24 AM (in response to Hans Wolffenbuttel)
Hi Hans.
Yes... this would be easy enough to do. Of course you'd need to analyse the class and make sure there's exactly only one possible target @ProcessMethod, but that's easy.
I think it could also be possible to support automatic unmarshalling/marshalling by detecting that the target @ProcessMethod is arg is JAXB annotated. So, if the payload was XML and the method arg was JAXB annotated, you could automatically trigger JAXB to create the objects from the payload XML.
Then, for unmarshalling other payload types (non-XML), or for unmarshalling into objects that are not JAXB annotated, or for servicing @ProcessMethods with multiple args.... you could allow unmarshalling by defining a smooks binding config on the action.
Anyway... we'll see
5. Re: Annotation based Action classesTom Fennelly Apr 24, 2010 4:29 AM (in response to Burr Sutter)
Hi Burr.
Yes... obviously testing would be easier since you don't need to deal with ConfigTree... just use setters. The @ConfigProperty can also be placed on a setter instead of the field.
As for an example config, you'd just need an action beforehand that performs a "to-Order" transform, setting the created Order on the Message payload.
Also, as hinted to above.... we could support auto-binding (unmarshalling).
6. Re: Annotation based Action classesEdgar Silva Apr 24, 2010 11:01 AM (in response to Tom Fennelly)
Tom,
That's is a very nice idea, I wrote a blog post in my blog about 2 years ago:
However, I had no chance to continue this job, but I vote that it could come as a good innovation for JBoss ESB
Edgar
7. Re: Annotation based Action classesBrad Davis May 11, 2010 8:04 AM (in response to Burr Sutter)
I actually would rather see some of the Action approaches @Deprecated. Right now, there are too many ways to create an action, which leads to too many test paths for the platform, and in the future, too many upgrade paths to maintain. Also, the lack of consistency here confuses customers when trying to decide on a "best approach".
For example, just in the quickstarts alone, I have see the following ways to create actions:
Some Actions extend AbstractActionLifecycle, some implement BeanConfiguredAction, others ActionPipelineProcessor, and still others AbstractActionPipelineProcessor.
8. Re: Annotation based Action classesKevin Conner May 11, 2010 8:52 AM (in response to Brad Davis)
Deprecation of other approaches, if and when that may happen, is a separate issue. Please do not derail this discussion by taking it off on a tangent.
Kev
9. Re: Annotation based Action classesDavid van Balen May 11, 2010 11:39 AM (in response to Tom Fennelly)
Would this approach allow for some default action behavior? For instance, allowing the user to specify an alternate response location for the action's result. I think basic functionality like that should be included in all actions by default, rather than having to rely on each action's developer re-inventing the wheel every time.
See for more on the above.
I also agree that this approach to action development, along with possibly one or two others that provide the same level of abstraction from the way messages and action configuration are implemented within the ESB, would need to be enforced as the standard methods for creating actions. Legacy actions would also need to be converted to use this approach so that issues like missing basic bahavior doesn't negatively affect future development.
10. Re: Annotation based Action classesTom Fennelly May 13, 2010 3:02 AM (in response to Tom Fennelly)
I commited what I have on this to a workspace in SVN:
I modified the http_gateway quickstart as one example:
In it you can see how the @ProcessMethod method is now taking multiple non ESB Message params. The params are annotated with @BodyParam and @PropertyParam annotations (@AttachmentParam also there), which tell the ESB from where on the Message to extract those params before invoking the process method @ProcessMethod.
@ProcessMethod public String printHttpRequestInfo(@BodyParam byte[] httpPayload, @PropertyParam HttpRequest requestInfo )
Those params can also take an explicit named location (e.g. @BodyParam("orderInfo")). These @XParam annotations are not required. If not present, the ESB will search the message based on param type, which is convenient but of course has the obvious "risks" that need to be kept in mind.
An example that also included a number of configurations would be better again (see use of the @ConfigProperty annotation), but I think/hope you get the picture.
The full FishEye changeset is
11. Re: Annotation based Action classesBrad Davis May 13, 2010 9:51 AM (in response to Tom Fennelly)
Tom, perhaps we should add another annotation for where the response should be placed back into the message.
Additionally, I think we should be able to override the default location annotations in the XML configurations.
12. Re: Annotation based Action classesJim Tyrrell May 20, 2010 4:25 PM (in response to Tom Fennelly)
@ProcessMethod should have a parameter like
@ProcessMethod(name="ProcessTheOrder")
This would give the tooling something to look at, reference that is not just a "ProcessMethod". What other meta data might need to be added to this tag, the gateway, listener, or is that just crazy talk?
13. Re: Annotation based Action classesTom Fennelly May 26, 2010 12:34 PM (in response to Jim Tyrrell)
Hey Jim... and what about the name of the process method itself... is it not the "name".. seems to me that adding a name annotation would be duplicating this, no?
14. Re: Annotation based Action classesJim Tyrrell May 26, 2010 12:48 PM (in response to Tom Fennelly)
But shouldn't you be able to change the name and give it a level of indirection. That is usually good in programming. Just a thought, and I agree the name can be the name, but what if you wanted to make it more friendly for business analysts and users. Or the method was named poorly in the past.