Time for action – examining exceptions

Let us now add an exception handler method to our MyAction class:

  1. Add the following method to the MyAction.java file:
    public void processException(final Message message,
        final Throwable th) {
        System.out.println("Something happened: " + th.getMessage());
    }
  2. Let us throw an exception deliberately from one of our process methods. Add a new method as follows:
    public Message causesException(Message message)
        throws ActionProcessingException {
            System.out.println("About to cause an exception");
            throw new ActionProcessingException("BAD STUFF HAPPENED");
        }
  3. Add the following import statement:
    import org.jboss.soa.esb.actions.ActionProcessingException;
  4. Open the jboss-esb.xml file and add another action with Name specified as "BadAction" to the service Class as "org.jboss.soa.esb.samples.chapter3.MyAction" and "causesException" as the Process method:
    Time for action – examining exceptions
  5. Add a new property to our BodyPrinter action. Enter Name as "exceptionMethod" and Value as "processException":
    Time for action – examining exceptions
  6. Click Finish and then Save.
  7. Deploy the application using the Run menu and select Run As | Run on Server.
  8. Run SendJMSMessage.java by clicking Run, select Run As | Java Application.

    The following will be displayed in the console

    INFO  [STDOUT] **************************************************
    INFO  [STDOUT] Body: Chapter 3 says Hello!
    INFO  [STDOUT] **************************************************
    INFO  [STDOUT] About to cause an exception
    INFO  [STDOUT] Something happened: BAD STUFF HAPPENED
    WARN  [ActionProcessingPipeline] No fault address defined for fault message!
    

What just happened?

You just created an exception processing method and threw an exception from another new action. You can see the exception bubble up to the first action and its processException method is called.

Have a go hero – extending from AbstractActionPipelineProcessor

Write a new action class that extends AbstractActionPipelineProcessor and see what methods are provided by default. See how the default methods get executed when you use this action in our service.

Dynamic methods

JBoss ESB can allow the service definition to request the dynamic invocation of methods within the action class, allowing the action class to provide alternative processing methods which can be chosen through the configuration. The signature of the methods being invoked dynamically must match the signature of the original methods as they are defined in the ActionPipelineProcessor interface.

The following example shows how the alternative method implementations could be defined within the action class.

public class DynamicAction extends AbstractActionLifecycle {
    public Message alternativeProcess(final Message message)
        throws ActionProcessingException  {
            ...
        }
    public void alternativeProcessSuccess(final Message message) {
        ...
    }
    public void alternativeProcessException(final Message message,
                                            final Throwable th) {
        ...
    }
}

These methods can then be used within the action configuration as follows:

<action class="DynamicAction" name="DynamicAction">
    <property name="process"
              value="alternativeProcess"/>
    <property name="okMethod"value="alternativeProcessSuccess"/>
    <property name="exceptionMethod"value="alternativeProcessException"/>
</action>

The configuration can specify multiple process methods, for example:

<property name="process" value="displayBody, displayHeader, displayContext"/>

This will result in each process method being invoked in sequence.

Have a go hero – multiple process methods

When we created the MyAction class we overrode the default process method with the displayMessage method. Now go ahead and add some more additional methods to displayBody, displayHeader, and so on, and see what appears in the console. Notice the order of execution as you defined in jboss-esb.xml.

MEP (Message Exchange Pattern) and responses

Any decision to send a response from a specific service pipeline is driven by three criteria:

  • The behavior of the actions within the service pipeline: Each action is given an opportunity to process the message as it progresses through the pipeline. It can then decide whether the pipeline should continue to process the subsequent actions (or not) by returning the message to be passed to the next action. If an action decides to terminate the pipeline early then it must return null as its response. If the last action returns a message then this will be considered as the service pipeline response, subject to the following conditions also being met.
  • The value specified for the service MEP attribute: The MEP (Message Exchange Pattern) attribute defines the intention of the current pipeline with regard to generating responses. The pipeline may represent one part of a composite service, in which case it does not determine how the composite service handles responses but rather the expectations of this individual section. The MEP can be defined as follows:

    Service MEP

    Service response behavior

    Undefined

    If the mep attribute is undefined then the response behavior is determined by whether the final action returns a message or not. If the final action returns a message then this will be considered as the response, otherwise the null response will terminate the pipeline without generating a response to the consumer.

    OneWay

    A OneWay MEP instructs the service pipeline to ignore the result of the final action and never process a response message, however a null response from an action can still cause the pipeline to terminate early.

    RequestResponse

    A RequestResponse MEP instructs the service pipeline to expect a response from the final action in the pipeline. Early termination of the pipeline, through one of the actions returning null, is considered exceptional behavior and will result in a warning message being emitted.

  • The routing information in the incoming message header: If the preceding conditions have been met, and a response message has reached the end of the pipeline, then the final decision on whether to send a response will lie with the consumer of the service. When the consumer invokes the service it can specify its expectations by including a ReplyTo or From EPR within the header of the original message. These values will be cached at the beginning of the pipeline and, once the pipeline has completed, these will be used to determine the target endpoint for any response. If there is no ReplyTo nor From EPR specified within the header of the original message then the consumer is explicitly stating that it does not wish to receive a normal response from the execution of the pipeline.

The decision process for sending a fault message back to the consumer is a much simpler process, relying solely on the routing information specified by the consumer of the service. If the routing information includes a FaultTo, ReplyTo, or From EPR then this will identify the endpoint that must be used as the target endpoint for receiving any fault message. This endpoint need not be the same as the one which will receive a response message and, in fact, the consumer may declare that it does not wish to receive a response message but that it is still interested in receiving fault messages.

ServiceInvoker

Each service deployed within the ESB must be associated with one or more ESB Aware Listeners, physical endpoints through which the service can be invoked. An ESB Aware Listener is simply one which receives a message by means of a transport mechanism and will pass it through to a service pipeline for execution.

The current transport mechanisms supported by ESB Aware Listeners are as follows:

Transport

Description

Java Message Service (JMS)

A transactional, Message Oriented Middleware (MOM) transport which supports delivery and consumption of messages using point-to-point (Queue) and publish/subscribe (Topic) models.

InVM

A transactional transport which supports delivery and consumption of messages within the same Java virtual machine, using a point-to-point (Queue) model. The transport has no persistent storage, resulting in a loss of messages should the virtual machine terminate.

SQL

A transactional transport which uses a database as the persistent storage mechanism, supporting delivery and consumption of messages using a point-to-point (Queue) model.

File/FTP/FTPS/SFTP

A non-transactional transport which uses a local file system or remote File Transfer Protocol server as the persistent storage mechanism.

The ESB Aware Listener, as part of its initialization, will create an opaque EPR which represents the physical endpoint through which a service can be addressed. This EPR will be associated with the service through registration within the Service Registry and will be removed from the registry once the physical endpoint is no longer active. Service consumers can then discover the EPRs associated with every provider of a service by querying the Service Registry.

Although accessing a service seems complicated, all details associated with querying the registry and communicating with the physical endpoints are taken care of by the org.jboss.soa.esb.client.ServiceInvoker utility class. The service consumer only has to handle the creation of the message and decide whether the invocation should be synchronous (requiring a response) or asynchronous (deferred or no response).

Note

The ServiceInvoker instance is intended to be cached by the consumer and reused for multiple invocations of the service. Creation of the ServiceInvoker will result in a query to the Service Registry, a relatively expensive operation, and this should be avoided when possible.

Synchronous delivery

Synchronous delivery is intended to be used by code requiring a response from a service before it can continue, such as the following:

final ServiceInvoker invoker = new ServiceInvoker(category, name) ;
final Message response = invoker.deliverSync(request, timeout) ;

The service consumer invokes the deliverSync method, specifying a timeout declaring how long it is prepared to wait for a response from the service invocation. An invocation may time out if the physical endpoint is no longer processing requests or if the load on the service is so great that it cannot process the request within the specified timeout period.

If the invocation does time out then the ServiceInvoker can choose to respond in one of two ways, depending on the current ESB configuration, they are as follows:

  • Throw a ResponseTimeoutException: No further attempts will be made to deliver the request to the service, however, the request may still be processed by the service provider.
  • Obtain an EPR representing a different physical endpoint and attempt delivery: The consumer will receive a response message if the next endpoint can process the request within the specified timeout period, however, the request may still be processed by the original endpoint. The application must be written to handle this scenario should it arise.

Asynchronous delivery

Asynchronous delivery can be used by code which does not expect a response or which is written to handle responses in an asynchronous manner, such as the following:

final ServiceInvoker invoker = new ServiceInvoker(category, name) ;
invoker.deliverAsync(request) ;

The service consumer does not wait for a response from the invocation, knowing that the message will be delivered and processed at some future point.

Using an asynchronous approach to invocations can result in an architecture that is more robust and performant than using synchronous delivery, after all a consumer which is not blocking while it waits for a response can be processing the next service request.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset