Custom actions

We'll start with custom actions to give you an understanding of the structure of an action class. There are three different approaches you can take to have your code function as a custom action:

  • Lifecycle actions
  • JavaBean actions
  • Custom actions using annotations

Lifecycle actions

The first approach is to create lifecycle actions.

These are used by many of the OOTB JBoss ESB actions. These actions implement the org.jboss.soa.esb.actions.ActionLifecycle interface, or its sub-interface org.jboss.soa.esb.actions.ActionPipelineProcessor.

You can see the list of these actions here:

http://docs.jboss.org/jbossesb/docs/4.10/javadoc/esb/org/jboss/soa/esb/actions/ActionLifecycle.html

The actions are listed in the javadoc as the classes implementing the interface. These actions implement the life-cycle model for an action through these methods:

  • initialize
  • destroy
  • process (ActionPipelineProcessor only)
  • processSuccess (ActionPipelineProcessor only)
  • processException (ActionPipelineProcessor only)

In this context, "lifecycle" refers to the lifecycle of a stateless action pipeline.

The initialize and destroy methods can be overridden to enable you to create resources that will be used throughout the execution of the action pipeline.

Any methods that you implement in your custom actions beyond these methods are located and executed by Java reflection.

To make things easier, abstract base classes (org.jboss.soa.esb.actions.AbstractActionPipelineProcessor and org.jboss.soa.esb.actions.AbstractActionLifecycle) that implement these interfaces are included with JBoss ESB. You can simply extend either of these abstract classes in your custom actions. These classes include sub methods for everything except the process methods.

The lifecycle actions have to include a constructor which uses an org.jboss.soa.esb.helpers.ConfigTree instance as a parameter. The ConfigTree refers to the configuration of the action.

Now let's look at some examples of lifecycle actions.

The simplest lifecycle action that you're likely to ever see is included in the "helloworld" quickstart. The lifecycle action is referenced in the jboss-esb.xml file as shown:

<action name="action1"
        class="org.jboss.soa.esb.samples.quickstart.helloworld.MyJMSListenerAction"
        process="displayMessage" />

What are the properties defined for this action? They are as follows:

  • name: A unique (again, unique within the given service) name for the action
  • class: The full class name for the custom action. We'll look at the source code for this action in a moment.
  • process: Remember how we talked about overriding the process method? This is an example.

Here's the source for the action (the file is under the quickstart helloworld directory: src/org/jboss/soa/esb/samples/quickstart/helloworld/MyJMSListenerAction.java):

package org.jboss.soa.esb.samples.quickstart.helloworld;
import org.jboss.soa.esb.actions.AbstractActionLifecycle;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.message.Message;
public class MyJMSListenerAction extends AbstractActionLifecycle {
    protected ConfigTree _config;
    public MyJMSListenerAction(ConfigTree config) {
        _config = config; }
    public Message displayMessage(Message message) throws Exception{
        System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
        System.out.println("Body: " + message.getBody().get()) ;
        System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
        return message;
    }
}

Let's take a closer look at this code:

  • The import statements bring in the AbstractActionLifecycle and ESB's message. The ConfigTree is needed by ESB to access the action's set of attributes, parse its XML configuration, and so on. The action's constructor must initialize the ConfigTree.
  • The class definition shows how the action class extends the AbstractActionLifecycle interface.
  • The displayMessage method definition corresponds to the overridden process method defined in the listener's definition in jboss-esb.xml.

The custom_action quickstart demonstrates these other types of lifecycle actions:

  • In the following lifecycle action, JBoss ESB looks for a method named process when the action fires:
    <action class="org.jboss.soa.esb.samples.quickstart.customaction.MyBasicAction"
            exceptionMethod="exceptionHandler" />
  • In the following lifecycle action, the three methods defined by the process property are executed in sequence, when the action fires:
    <action class="org.jboss.soa.esb.samples.quickstart.customaction.StatefulAction"
            process="methodOne,methodTwo,displayCount"
            exceptionMethod="exceptionHandler" />
  • The following lifecycle action shows you can create your own custom attributes for the action tag and even have child elements for that action. As the quickstart's documentation points out, this approach can be used to make the action more easily configurable, as follows:
    <action class="org.jboss.soa.esb.samples.quickstart.customaction.CustomConfigAction"
            process="displayConfig" myStuff="rocks"moreStuff="rocks harder">
        <subElement1>Value of 1</subElement1>
        <subElement2>Value of 2</subElement2>
        <subElement3>Value of 3</subElement3>
    </action>

JavaBean actions

The second approach for building custom actions is to create JavaBean actions. These actions implement the org.jboss.soa.esb.actions.BeanConfiguredAction interface. These actions are differentiated from the lifecycle actions in several ways, as follows:

  • They set properties with "setter" methods. These methods map to the actions' property names.
  • They do not support the lifecycle methods (initialize, destroy, process, processSuccess, and processException). Instead, these actions are instantiated when a message is processed by the action pipeline.
  • Unlike lifecycle actions, JavaBean actions' process methods are always executed through Java reflection.

An example of this type of action is also illustrated in the custom_action quickstart:

<action name="seventh"
        class="org.jboss.soa.esb.samples.quickstart.customaction.CustomBeanConfigAction">
    <property name="information" value="Hola Mundo" />
    <property name="repeatCount" value="5"/>
</action>

In this action definition, the bean's setter methods will be invoked with the properties defined in the jboss-esb.xml file.

And here's a fragment from the org.jboss.soa.esb.samples.quickstart.customaction.CustomBeanConfigAction class. Note that the setter methods correspond to the property names:

public void setInformation(String information) {
    this.information = information;
}
public void setRepeatCount(Integer repeatCount) {
    this.repeatCount = repeatCount;
}
    public Message process(Message message) throwsActionProcessingException {
    System.out.println("[" + serviceCategory + ":" +serviceName + "] Repeat message: " + information +" " + repeatCount + " times:");
    for (int i=0; i < repeatCount; i++) {
        System.out.println(information);
    }
    return message;
}

Custom actions using annotations

One common trend in Java programing is that of simplifying complex structures and technologies with annotations. For example, EJB3 removed several of the complex and annoying requirements of EJB2 through the use of annotations. The third approach to creating custom actions that JBoss ESB provides is an annotation mechanism through which an action class can be created and configured. In order for the class to be identified as an annotated action, one or more of its public methods must be annotated with the org.jboss.soa.esb.actions.annotation.Process annotation.

When using an annotated action class it is no longer necessary to handle the ConfigTree, the configuration being handled through annotating fields or setter methods from within the class. There are some restrictions in the configuration types which can be used through this mechanism.

Fields and setter methods should be annotated with the org.jboss.soa.esb.configure.ConfigProperty annotation, for example:

@ConfigProperty
private int intConfig;

@ConfigProperty(use=Use.OPTIONAL)
private String stringConfig;

@ConfigProperty(name="AlternativeName")
public void setEnumConfig(final MyEnum value) {
  ...
}

The ConfigProperty annotation can be configured through the following annotation elements:

  • name: An optional element which defines the ConfigTree attribute name. If this element is not specified then the attribute name will match the name of the field or will be derived from the setter method using the JavaBean conventions.
  • use: An optional element which defines whether the property is REQUIRED or OPTIONAL, defaulting to REQUIRED. It is an error if a REQUIRED property cannot be assigned a value.
  • DefaultVal: An optional element which defines the default value to use for the property if a value has not been specified within the action configuration.
  • Choice: An optional element which restricts the property values to a specified set. It is an error if a property is configured to a value not present within the choice set.

Note

Note that annotations using the ConfigTree annotation can only be configured using simple name/value properties, it is not possible to use hierarchical configurations nor to traverse the ConfigTree hierarchy. The property types must be primitive or must define a constructor taking a single String parameter.

Lifecycle annotations

An annotated action can define any number of public initialization methods, each of which must be annotated with the org.jboss.soa.esb.lifecycle.annotation.Initialize annotation. For example:

@Initialize
public void firstInit() {
    ...
}

@Initialize
public void secondInit(final ConfigTree configTree)
           throws ActionLifecycleException {
    ...
}

The Initialize methods may take an optional ConfigTree parameter and may throw an ActionLifecycleException.

An annotated action can also define any number of public destroy methods, each being annotated with the org.jboss.soa.esb.lifecycle.annotation.Destroy annotation. For example:

@Destroy
public void firstDestroy() {
    ...
}

@Destroy
public void secondDestroy(final ConfigTree configTree)
            throws ActionLifecycleException {
    ...
}

The Destroy methods may take an optional ConfigTree parameter and may throw an ActionLifecycleException.

Processing annotations

An annotated action can define any number of public process methods, each being annotated with the org.jboss.soa.esb.actions.annotation.Process annotation, however only one method may be executed and this must be chosen through the action configuration.

@Process
public Message process(final Message message)throws    ActionProcessingException {
    ...
}

Process methods may be defined with any number of parameters and may choose not to return a value, for example:

// method expecting the default message payload to be of type MyType,
// returning a String value for the response payload.
@Process
public String processMyType(final MyType payload) {
    ...
}

// method accessing the full message without updating
// the response payload
@Process
public void processMessage(final Message message) {
    ...
}

// method ignoring message contents and updating response payload
@Process
public MyType process() {
    ...
}

The parameter values passed to a process method may be configured using a number of annotations; if none are present then the values are resolved as follows:

  • Message type: Pass the current message as the parameter.
  • Type matches default payload type: Pass the default payload as the parameter.
  • Other type: Locate an entry in the message body, property, or attachment which can be assigned to the parameter type.
  • org.jboss.soa.esb.actions.annotation.BodyParam: This annotation takes an optional value which identifies which part of the message body to pass to the method. If not specified then the parameter is resolved by searching through all entries in the message body for the first value which can be assigned to the parameter type.
  • org.jboss.soa.esb.actions.annotation.PropertyParam: This annotation takes an optional value which identifies which part of the message properties to pass to the method. If not specified then the parameter is resolved by searching through all entries in the message properties for the first value which can be assigned to the parameter type.
  • org.jboss.soa.esb.actions.annotation.AttachmentParam: This annotation takes an optional value which identifies which part of the message attachments to pass to the method. If not specified then the parameter is resolved by searching through all entries in the message attachments for the first value which can be assigned to the parameter type.

Examples of these annotations are as follows:

public String processAnnotations(@BodyParam("MyBody") MyBodyType body,
       @PropertyParam("MyProperty") Integer property,
       @AttachmentParam("MyAttachment") byte[] attachment) {
    ...
}

Note

Note that relying on any of the cascading searches through body, property, and attachments sections of the message could result in a non-deterministic resolution of the parameter if more than one entry may be assigned to the property type.

An annotated action can define any number of public processSuccess methods, each of which must be annotated using the org.jboss.soa.esb.actions.annotation.OnSuccess annotation. Each processSuccess method will be invoked when a successful invocation of the pipeline has occurred and may be defined with no parameters or with a single Message parameter, for example:

@OnSuccess
public void firstSuccess() {
    ...
}

@OnSuccess
public void secondSuccess(final Message message) {
    ...
}

An annotated action may also define any number of public processException methods, each of which must be annotated using the org.jboss.soa.esb.actions.annotation.OnException annotation. Each processException method will be invoked when an exception is raised during an invocation of the pipeline and may be defined with no parameters, a single Message parameter or a Message and Throwable parameters, for example:

@OnException
public void firstException() {
    ...
}

@OnException
public void secondException(final Message message) {
    ...
}

@OnException
public void thirdException(final Message message, final Throwable th) {
    ...
}
..................Content has been hidden....................

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