There are many ways to achieve what you are describing, and determining which one of them is most appropriate depends on many factors of your particular scenario. Let's go for just one of them to illustrate the point.
Steps 1 and 2 seem quite simple: configure a first element in your xml configuraton, for example Steps1And2 (see code below). Your action class has to extend AbstractFileAction (because your listenerClass is DirectoryPoller)
Following this step, your original file will now reside wherever you have specified using the errorDirURI, errorSuffix, postDirURI, postSuffix attributes in your configuration. If your validate action class threw some exception the file will end up in the error directory (with the corresponding errorSuffix). If it did not, it will be moved to the postDirUIR (with postSuffix)
The easiest way of chaining steps 3 and 4 would be to use a NotificationList with type attribute = "ok". This element can have one or more child elements, so you can trigger more than one action classes in parallel. Let's go for the simplest :
The getOkNotification() of your first action class can return a String with the full path of the file that was copied to wherever you specified in postDirUIR (keep in mind that it will have a suffix with what was defined in postSuffix).
Add a second element to your xml (a sibling of <Steps1And2>) e.g. (see code below). (here your action class has to extend AbstractAction as your listener class is JmsQueueListener)
Note that we are always using queue/A but your message selector will filter only what the of the previous element sent in the NotificationList type="ok".
The NotificationList of this second step also has only one target. Keep in mind that a powerful feature is the ability to trigger parallel events (and thus parallel action classes) by specifying more than one element (potentially of different types).
It also specifies a different value for the same message property (it could very well be a different message property, but we arbitrarily chose the same one)
The getOkNotification() method of your action class allows you to determine what goes in the message that the <target class ="NotifyQueues> will eventually send. The action class that is triggered by the listener that picks up this notification should know what to do with that.
You can chain as many listeners as you choose to, by adding elements to your xml configuration document.
In order to better understand how to build your xml configuration files, please take a look at the GpListenerXmlConfiguration.xls and NotificationXmlConfiguration.xls files in the .../product/docs directory of the jbossEsb download
Good luck !
<JohanExample> <Steps1And2 listenerClass="org.jboss.soa.esb.listeners.DirectoryPoller" actionClass="yourpackage.YourValidateAction" ... ... > <NotificationList type="OK"> <target class="NotifyQueues" > <queue jndiName="queue/A"> <messageProp name="whateverPropYouwish" value="valid" /> </queue> </target> </NotificationList> </Steps1And2> <DoSomethingElseStep listenerClass="org.jboss.soa.esb.listeners.JmsQueueListener" actionClass="yourpackage.YourDoSomethingAction" listenQueue="queue/A" listenMsgSelector="whateverPropYouwish='valid'" ... ... > <NotificationList type="OK"> <target class="NotifyQueues" > <queue jndiName="queue/A"> <messageProp name="whateverPropYouwish" value="somethingElseWasDone" /> </queue> </target> </NotificationList> </DoSomethingElseStep> <WhateverElseStep listenerClass="org.jboss.soa.esb.listeners.JmsQueueListener" actionClass="yourpackage.AnotherActionClass" listenQueue="queue/A" listenMsgSelector="whateverPropYouwish='somethingElseWasDone'" ... ... > </WhateverElseStep> You can have more elements at this level (see GpListenerXmlConfiguration.xls in .../product/docs directory of the jbossEsb download) </JohanExample>
The 4th Quickstart has a basic example of this concept:
At the moment it has a directory/file poller that notifies a JMS queue and then a JMS queue listener that responds. You can combine the examples into a single config file instead of the 2 that I show.
What do you think?
Thank you for your answers, This is clear to me now.
But what if I would like to rollback/commit a transaction based on the success of all actions? Seems to me that this is impossible to implement with this architecture (and not intended to solve this problem?)?
Of course, it´s easy to create an Action wich in turn can instantiate multiple Actions (or some other more suitable Interface) and in this way solve this issue.
All of the actions are presently decoupled and operate async in the current Beta architecture. Not too mention it is challenging for a FTP server, file drop service, etc to behave transactionally and most ESB providers will indicate that transactions only work across transactional resources.
However, it should be noted that the team behind JBoss ESB is also the team behind JBoss Transactions who have successfully created a WS-AtomicTransaction and WS-BusinessActivity implementation (check out JBoss Transactions).
I'm not aware of transaction support in the first GA release of JBoss ESB but it is clearly not out of the question for a later release.
This is the only topic that mentions the NotificationList element. I looked in the code and found out that you can use notifications for success or error. However all 4 quickstart samples use only the "success" feature. Can someone provide a sample with a failure notification? I suppose you have to place something like
<NotificationList type="ERR"> ... </NotificationList>
But what other conditions have to be in place? How do you trigger the failure method?
Also, I tried to use the
<property name="exceptionMethod" value="exceptionHandler"/> <property name="okMethod" value="logSuccess"/>
methods for a chain of actions. From what I read in the programmer guide, I was under the impression that after each action the success or error method would fire (this part):
Callback method for success in each <action> element: If the list of
methods in the 'process' attribute was executed successfully, the
pipeline will analyze contents of the 'okMethod' attribute. If none is
specified, processing will continue with the next <action> element.
Instead, I found out that the success methods are all triggered at the end of the processing:
If a method name is provided in the 'okMethod' attribute, it will be invoked using the Message returned by the last method in step 3
, which kind of defeats the purpose, doesn't it?
I mean, I need to track a message going through several steps, and log each one in the DB (maybe even the entire message as it is at that step), for example:
[listener] -> [log message received] -> [step 1] -> [log success of 1] -> [step 2] -> [log success of 2] -> [notifier] -> [log success of notifier]
This would enable me to pinpoint the step where I would get an error in the chain.
Instead, I get:
[listener] -> [step 1] -> [step 2] -> [notifier] -> [log message received] -> [log success of 1] -> [log success of 2] -> [log success of notifier]
So if I get an error in step 2, for example, it seems that the exceptionMethod for the entire chain will be triggered.
This would mean that I will have to log the success via custom methods, called from the processing methods :(.
It looks like there is an error in the documentation.
The action processing pipeline works as follows
[process action1] -> [process action2] -> [process action3] -> [success action3] -> [success action2] -> [success action1]
If there is an error in action 2 then you will see the following
[process action1] -> [process action2] -> [error action2] -> [error action1]
The success/error invocations are made in the reverse order to the processing ones.
The ActionProcessingPipelineUnitTest class contains tests for the different permutations of invocations and types of actions we support.
There appears to be a signature error in the Notifier class which would prevent the exception reporting from working. I'll check this out later and create a JIRA issue if this is the case.
Can you proceed using normal actions in the meantime?
Not the chain of events I was expecting.
Would you be interested in defining a "behavior" for the way the methods are executed?
I mean you may want:
I would also consider a normal behavior (and what will probably need to be implemented in our project):
Not the chain of events I was expecting.
It's not? This behaviour will allow preceeding actions to react to errors generated further along the action chain, assuming they wish to. If you search specifications which contain similar processing then you will find them following the same ordering.
It should be possible to achieve both of these by defining new actions for processing, similar to the way the Notifier is currently done.