Let us now add an exception handler method to our MyAction
class:
MyAction.java
file:public void processException(final Message message, final Throwable th) { System.out.println("Something happened: " + th.getMessage()); }
public Message causesException(Message message) throws ActionProcessingException { System.out.println("About to cause an exception"); throw new ActionProcessingException("BAD STUFF HAPPENED"); }
import
statement:import org.jboss.soa.esb.actions.ActionProcessingException;
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:BodyPrinter
action. Enter Name as "exceptionMethod" and Value as "processException":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!
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.
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.
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.
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
.
Any decision to send a response from a specific service pipeline is driven by three criteria:
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.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.
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:
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).
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:
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.