Version 43

    Overview

     

    The JBoss ESB beta1 release supported a 1:1 listener to action-class message processing model. 

     

    For example, the following configuration snippet is from the beta1 Trailblazer Configuration:

    +

               <CreditAgencyJMSOutput
                          listenerClass="org.jboss.soa.esb.listeners.JmsQueueListener"
                          actionClass="org.jboss.soa.esb.samples.loanbroker.actions.ProcessCreditResponse"
    
                                     ... etc
    
               </CreditAgencyJMSOutput>

    +

     

    As part of migrating the ESB architecture towards the GA target arhitecture, we've changed how listeners and actions work.  We now support a 1: listener to action-class message processing model.  So, the Trailblazer Configuration now looks like this:

    +

               <CreditAgencyJMSOutput
                          listenerClass="org.jboss.soa.esb.listeners.JmsQueueListener"
                          actions="CreditCheckResponse-To-BankQuote, Route-BankQuote-To-JMSBank-Router, BankQuote-To-CSV, Route-BankQuote-CSV-To-FileBank"
    
                                     ... etc
    
               </CreditAgencyJMSOutput>

    +

     

    So, as you can see from the above config extract, instead of having a single action handler per listener we now support a "pipeline" of actions to be performed on the message received by the action listener.  Each processing action output feeds into the next action processor in the pipeline.

     

    So how does all this help us move towards the GA architecture?

    A number of changes that were made as part of introducing the pipeline architecture should help us move towards the GA target arhitecture:

    1. Diapatcher Model: The concept of a pipeline architecture is quite similar to to the ideas behind the "Dispatcher" model.

    2. Decoupling from Delivery Channel: As part of implementing the pipeline architecture, we've managed to decouple the "out of the box" action handling processors from details related to the underlying deliver channel (JMS, Filesys etc).  As an examples of this, compare the AbstractSqlRowAction processor before and after, or the AbstractFileAction processor before and after.  The notification and channel management related code that was in these classes is now handled by their respective channel message listeners.  This has 2 positive side effects;

      1. should make it a lot easier for us to introduce some form of "normalised" message structure as laid down in the GA architecture

      2. simplifies unit testing of action processor implemetnations.

    3. More Reusable Code: The pipeline architecture facilitates the developement of smaller and more reusable action handlers that can be plugged together in different ways.  With the old single-action-handler model this was more difficult because it meant either passing messages between listeners (extra config and processing overhead), or implementing all the functionality in one monolithic handler (much less reusable).  This should help us move forward simply because it should mean that any action handler (dispatcher) code we write should be more reusable no matter how we evolve the architecture.

     

     

    Action Configurations

     

    In the old model, the ESB configuration specified a single actionClass per listener configuration as outlined above.  This new model specifies a comma seperated list of action names.  These action configurations are configured as shown in the following extract from the Trailblazer Configuration:

     

         <Actions>
              <Action name="ProcessCreditCheckRequest" processor="CreditRequestProcessor" ></Action>
              
              <Action name="Route-CreditCheckResponse-To-CreditCheckResponseProcessor" processor="JMSRouter">
                   <property name="jndiName" value="queue/A" ></property>
                          <property name="message-prop:sample_loanbroker_servicecode" value="creditResponse" ></property>
              </Action>
              
              <Action name="CreditCheckResponse-To-BankQuote" processor="CreditResponseProcessor" ></Action>
              
              <Action name="Route-BankQuote-To-JMSBank-Router" processor="JMSRouter">
                   <property name="jndiName" value="queue/A" ></property>
                          <property name="message-prop:sample_loanbroker_servicecode" value="BankQuoteObject" ></property>
              </Action>
              
              <Action name="Route-BankQuote-XML-To-JMSBank" processor="JMSRouter">
                   <property name="jndiName" value="queue/C" ></property>
              </Action>
    
              <Action name="BankQuote-To-CSV" processor="ObjectToCSVString">
                   <property name="bean-properties" value="ssn,creditScore,historyLength,loanAmount,loanTerm,customerUID" ></property>
              </Action>
    
              <Action name="Route-BankQuote-CSV-To-FileBank" processor="ObjectToFileWriter">
                   <property name="file" value="./@trail.runtime.dir@/BankInput" ></property>
                   <property name="ext" value="dat" ></property>
              </Action>
    
              <Action name="ObjectToXStream" processor="ObjectToXStream" ></Action>
    
              <Action name="FileToByteArray" processor="FileToByteArray" ></Action>
    
              <Action name="Bytes-To-UTF-8-String" processor="ByteArrayToString">
                   <property name="encoding" value="UTF-8" ></property>
              </Action>
    
              <Action name="BankQuoteResponseCSV-To-BankQuoteResponse" processor="ToBankQuoteResponse" ></Action>
              <Action name="BankQuoteResponseXML-To-BankQuoteResponse" processor="ToBankQuoteResponse" ></Action>
    
              <Action name="Process-BankQuote" processor="ProcessBanksResponse" ></Action>
    
              <ProcessorAliases>
                   <Alias name="CreditRequestProcessor" class="org.jboss.soa.esb.samples.loanbroker.actions.ProcessCreditRequest" ></Alias>
                   <Alias name="JMSRouter" class="org.jboss.soa.esb.actions.JMSRouter" ></Alias>
                   <Alias name="CreditResponseProcessor" class="org.jboss.soa.esb.samples.loanbroker.actions.ProcessCreditResponse" ></Alias>
                   <Alias name="ObjectToCSVString" class="org.jboss.soa.esb.actions.ObjectToCSVString" ></Alias>
                   <Alias name="ObjectToFileWriter" class="org.jboss.soa.esb.actions.ObjectToFileWriter" ></Alias>
                   <Alias name="FileToByteArray" class="org.jboss.soa.esb.actions.FileToByteArray" ></Alias>
                   <Alias name="ByteArrayToString" class="org.jboss.soa.esb.actions.ByteArrayToString" ></Alias>
                   <Alias name="ObjectToXStream" class="org.jboss.soa.esb.samples.loanbroker.actions.ObjectToXStream" ></Alias>
                   <Alias name="ToBankQuoteResponse" class="org.jboss.soa.esb.samples.loanbroker.actions.ToBankQuoteResponse" ></Alias>
                   <Alias name="ProcessBanksResponse" class="org.jboss.soa.esb.samples.loanbroker.actions.ProcessBanksResponse" ></Alias>
              </ProcessorAliases>
         </Actions>
    

     

    From this you can see that each action configuration has the following:

    1. A name.

    2. A processor.

    3. An action property list.

     

     

    Actions Out Of The Box...

     

    We have a number of reusable action processors available from the current codebase.  All of these are in use in the Trailblazer:

     

     

    New Abstract Listener...

    We've created a new AbstractListener class that all listener implementations should extend.  This class was generalised from the original AbstractPoller and JmsQueueListener classes.  This class defines an abstract receive method and houses the code for executing the pipeline on the received message objects - see the ActionProcessingPipeline inner class.

     

    If this class stays in existence its workings should probably be evolved further.  The model should change such that this class is injected with a listener implementation where the responsibilities are as follows:

     

    "This Class":

    1. Blocks on the injected "listener" implementation's receive method.

    2. Executes the pipeline process on the received message objects.

    3. Calls the other listener lifecycle management methods.

     

    Listners:

    1. Listen for messages in their receive method implementation.

    2. Perform whatever channel specific message normalisation needs to be performed.

    3. Return the messages to the receive method caller.

    4. Handle listener lifecycle management methods calls e.g. for the DirectoryPoller - delete the working file when the processingComplete method is called.