23 min read

(For more resources on topic_name, see here.)

Preparing JBoss Developer Studio

The examples in this article are based on a standard ESB application template that can be found under the Chapter3 directory within the sample downloads..We will modify this template application as we proceed through this chapter.

Time for action – opening the Chapter3 app

Follow these steps:

  1. Click on the File menu and select Import.
  2. Now choose Existing Projects into workspace and select the folder where the book samples have been extracted:

  3. Then click on Finish. Now have a look at the jboss-esb.xml file. You can see that it has a single service and action as defined in the following snippet:

    <jbossesb parameterReloadSecs="5"


    xsi_schemaLocation="http://anonsvn.labs.jboss.com/labs/
    jbossesb/trunk/product/etc/schemas/xml/
    jbossesb-1.3.0.xsd
    http://anonsvn.jboss.org/repos/labs/
    labs/jbossesb/trunk/product/etc/
    schemas/xml/jbossesb-1.3.0.xsd">
    <providers>
    <jms-provider connection-factory="ConnectionFactory"
    name="JBossMQ">
    <jms-bus busid="chapter3GwChannel">
    <jms-message-filter dest-name="queue/chapter3_Request_gw"
    dest-type="QUEUE"/>
    </jms-bus>
    <jms-bus busid="chapter3EsbChannel">
    <jms-message-filter dest-name="queue/chapter3_Request_esb"
    dest-type="QUEUE"/>
    </jms-bus>
    </jms-provider>
    </providers>
    <services>
    <service category="Chapter3Sample"
    description="A template for Chapter3"
    name="Chapter3Service">
    <listeners>
    <jms-listener busidref="chapter3GwChannel"
    is-gateway="true"
    name="Chapter3GwListener"/>
    <jms-listener busidref="chapter3EsbChannel"
    name="Chapter3Listener"/>
    </listeners>
    <actions mep="OneWay">
    <action class="org.jboss.soa.esb.actions.SystemPrintln"
    name="PrintBefore">
    <property name="message"/>
    <property name="printfull" value="true"/>
    </action>
    </actions>
    </service>
    </services>
    </jbossesb>

Examining the structure of ESB messages

A service is an implementation of a piece of business logic which exposes a well defined service contract to consumers. The service will provide an abstract service contract which describes the functionality exposed by the service and will exhibit the following characteristics:

  • Self contained: The implementation of the service is independent from the context of the consumers; any implementation changes will have no impact.
  • Loosely coupled: The consumer invokes the service indirectly, passing messages through the bus to the service endpoint. There is no direct connection between the service and its consumers.
  • Reusable: The service can be invoked by any consumer requiring the functionality exposed by the service. The provider is tied to neither a particular application nor process.

Services which adhere to these criteria will be capable of evolving and scaling without affecting any consumers of that service. The consumer no longer cares which implementation of the service is being invoked, nor where it is located, provided that the exposed service contract remains compatible.

Examining the message

The structure of the message, and how it can be manipulated, plays an important part in any ESB application as a result of the message driven nature of the communication between service providers and consumers. The message is the envelope which contains all of the information relevant to a specific invocation of a service.

All messages within JBoss ESB are implementations of the org.jboss.soa.esb.message. Message interface, the major aspects of which are:

  • Header: Information concerning the identity, routing addresses, and correlation of the message
  • Context: Contextual information pertaining to the delivery of each message, such as the security context
  • Body: The payload and additional details as required by the service contract
  • Attachment: Additional information that may be referenced from within the payload
  • Properties: Information relating to the specific delivery of a message, usually transport specific (for example the original JMS queue name)

Time for action – printing the message structure

Let us execute the Chapter3 sample application that was opened up at the beginning of this chapter. Follow these steps:

  1. In JBoss Developer Studio, click Run and select Run As and Run on Server. Alternatively you can press Alt + Shift + X, followed by R.

  2. You can see the server runtime has been pre-selected. Choosing the Always use this server when running this project check box will always use this runtime and this dialog will not appear again.
  3. Click Next. A window with the project pre-configured to run on this server is shown. Ensure that we have only our project Chapter3 selected to the right hand side.
  4. Click Finish.
  5. The server runtime will be started up (if not already started) and the ESB file will be deployed to the server runtime.
  6. Select the src folder, expand it till the SendJMSMessage.java file is displayed in the tree. Now click Run, select Run As and Java Application.

The entire ESB message contents will be printed in the console as follows:

INFO [STDOUT] Message structure:
INFO [STDOUT] [ message: [ JBOSS_XML ]
header: [ To: JMSEpr [ PortReference < <wsa:Address
jms:localhost:1099#queue/chapter3_Request_esb/>,
<wsa:ReferenceProperties jbossesb:java.naming.factory.
initial : org.jnp.interfaces.NamingContextFactory/>,
<wsa:ReferenceProperties jbossesb:java.naming.provider.url :
localhost:1099/>, <wsa:ReferenceProperties jbossesb:java.naming.
factory.url.pkgs : org.jnp.interfaces/>, <wsa:ReferenceProperties
jbossesb:destination-type : queue/>, <wsa:ReferenceProperties
jbossesb:destination-name : queue/chapter3_Request_esb/>,
<wsa:ReferenceProperties jbossesb:specification-version :
1.1/>, <wsa:ReferenceProperties jbossesb:connection-factory :
ConnectionFactory/>, <wsa:ReferenceProperties jbossesb:persistent :
true/>, <wsa:ReferenceProperties jbossesb:acknowledge-mode : AUTO_
ACKNOWLEDGE/>, <wsa:ReferenceProperties jbossesb:transacted : false/>,
<wsa:ReferenceProperties jbossesb:type : urn:jboss/esb/epr/type/
jms/> > ] MessageID: e694a6a5-6a30-45bf-8f6d-f48363219ccf RelatesTo:
jms:correlationID#e694a6a5-6a30-45bf-8f6d-f48363219ccf ]
context: {}
body: [ objects: {org.jboss.soa.esb.message.defaultEntry=Chapter 3
says Hello!} ]
fault: [ ]
attachments: [ Named:{}, Unnamed:[] ]
properties: [ {org.jboss.soa.esb.message.transport.type=Deferred
serialized value: 12d16a5, org.jboss.soa.esb.message.byte.size=2757,
javax.jms.message.redelivered=false, org.jboss.soa.esb.gateway.
original.queue.name=Deferred serialized value: 129bebb, org.jboss.soa.
esb.message.source=Deferred serialized value: 1a8e795} ] ]

What just happened?

You have just created a Chapter3.esb file and deployed it to the ESB Runtime on the JBoss Application Server 5.1. You executed a gateway client that posted a string to the Bus. The server converted this message to an ESB message and the complete structure was printed out. Take a moment to examine the output and understand the various parts of the ESB message.

Have a go hero – deploying applications

Step 1 through step 4 describe how to start the server and deploy our application from within JBoss Developer Studio. For the rest of this chapter, and throughout this book, you will be repeating these steps and will just be asked to deploy the application.

Message implementations

JBoss ESB provides two different implementations of the message interface, one which marshalls data into an XML format and a second which uses Java serialization to create a binary representation of the message. Both of these implementations will only handle Java serializable objects by default, however it is possible to extend the XML implementation to support additional object types.

Message implementations are created indirectly through the org.jboss.soa.esb. message.format.MessageFactory class.

In general any use of serializable objects can lead to a brittle application, one that is more tightly coupled between the message producer and consumer. The message implementations within JBoss ESB mitigate this by supporting a ‘Just In Time’ approach when accessing the data. Care must still be taken with what data is placed within the message, however serialization/marshalling of these objects will only occur as and when required.

Extending the ESB to provide alternative message implementations, and extending the current XML implementation to support additional types, is outside the scope of this book.

The body

This is the section of the message which contains the main payload information for the message, adhering to the contract exposed by the service. The payload should only consist of the data required by the service contract and should not rely on any service implementation details as this will prevent the evolution or replacement of the service implementation at a future date.

The types of data contained within the body are restricted only by the requirements imposed by the message implementation, in other words the implementation must be able to serialize or marshall the contents as part of service invocation.

The body consists of

  • Main payload: accessed using the following methods:
  • public Object get() ;
    public void add(final Object value) ;

  • Named objects: accessed using the following methods:
  • public Object get(final String name) ;
    public void add(final String name, final Object value) ;

Time for action – examining the main payload

Let us create another action class that simply prints the message body. We will add this action to the sample application that was opened up at the beginning of this chapter.

  1. Right click on the src folder and choose New and select Class:
  2. Enter the Name as “MyAction”, enter the Package as “org.jboss.soa. samples.chapter3”, and select the Superclass as “org.jboss.soa.esb. actions.AbstractActionLifecycle”:
  3. Click Finish.
  4. Add the following imports and the following body contents to the code:
  5. import org.jboss.soa.esb.helpers.ConfigTree;
    import org.jboss.soa.esb.message.Message;

    protected ConfigTree _config;
    public MyAction(ConfigTree config) {
    _config = config;
    }
    public Message displayMessage(Message message) throws Exception {
    System.out.println(
    "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
    System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
    System.out.println("Body: " + message.getBody().get());
    System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
    return message;
    }

  6. Click Save.
  7. Open the jboss-esb.xml file in Tree mode, expand till Actions is displayed in the tree. Select Actions, click Add | Custom Action:
  8. Enter the Name as “BodyPrinter” and choose the “MyAction” class and “displayMessage” process method:
  9. Click Save and the application will be deployed. If the server was stopped then deploy it using the Run menu and select Run As | Run on Server:
  10. Once the application is deployed on the server, run SendJMSMessage.java by clicking Run | Run As | Java Application.
    The following can be seen displayed in the console output:
  11. 12:19:32,562 INFO [STDOUT] &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
    12:19:32,562 INFO [STDOUT] Body: Chapter 3 says Hello!
    12:19:32,562 INFO [STDOUT] &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

What just happened?

You have just created your own action class that used the Message API to get the main payload of the message and printed it to the console.

Have a go hero – additional body contents

Now add another miscellaneous SystemPrintln action after our BodyPrinter. Name it PrintAfter and make sure printfull is set to true. Modify the MyAction class and add additional named content using the getBody().add(name, object) method and see what gets printed on the console.

Here is the actions section of the config file

<actions mep="OneWay">
<action class="org.jboss.soa.esb.actions.SystemPrintln"
name="PrintBefore">
<property name="message"/>
<property name="printfull" value="true"/>
</action>
<action class="org.jboss.soa.esb.samples.chapter3.MyAction"
name="BodyPrinter" process="displayMessage"/>
<action class="org.jboss.soa.esb.actions.SystemPrintln"
name="PrintAfter">
<property name="message"/>
<property name="printfull" value="true"/>
</action>
</actions>

The following is the listing of the MyAction class’s modified displayMessage method

public Message displayMessage(Message message) throws Exception {
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
System.out.println("Body: " + message.getBody().get());
message.getBody().add("Something", "Unknown");
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
return message;
}

The header

The message header contains the information relating to the identity, routing, and the correlation of messages. This information is based on, and shares much in common with, the concepts defined in the W3C WS-Addressing specification.

It is important to point out that many of these aspects are normally initialized automatically by other parts of the codebase; a solid understanding of these concepts will allow the developer to create composite services using more advanced topologies.

Routing information

Every time a message is sent within the ESB it contains information which describes who sent the message, which service it should be routed to, and where any replies/faults should be sent once processing is complete. The creation of this information is the responsibility of the invoker and, once delivered, any changes made to this information, from within the target service, will be ignored by that service.

The information in the header takes the form of Endpoint References (EPRs) containing a representation of the service address, often transport specific, and extensions which can contain relevant contextual information for that endpoint. This information should be treated as opaque by all parties except the party which was responsible for creating it.

There are four EPRs included in the header, they are as follows:

  • To: This is the only mandatory EPR, representing the address of the service to which the message is being sent. This will be initialized by ServiceInvoker with the details of the service chosen to receive the message.
  • From: This EPR represents the originator of the message, if present, and may be used as the address for responses if there is neither an explicit ReplyTo nor FaultTo set on the message.
  • ReplyTo: This EPR represents the endpoint to which all responses will be sent, if present, and may be used as the address for faults if there is no explicit FaultTo set on the message. This will normally be initialized by ServiceInvoker if a synchronous response is expected by the service consumer.
  • FaultTo: This EPR represents the endpoint to which all faults will be sent, if present.

When thinking about the routing information it is important to view these details from the perspective of the service consumer, as the EPRs represent the wishes of the consumer and must be adhered to. If the service implementation involves more advanced topologies, like chaining and continuations, which we will discuss later in the chapter, then care must be taken to preserve these EPRs when messages are propagated to subsequent services.

Message identity and correlation

There are two parts of the header which are related to the identity of the message and its correlation with a preceding message. These are as follows:

  • MessageID: A unique reference which can be used to identify the message as it progresses through the ESB. The reference is represented by a Uniform Resource Name (URN), a specialized Uniform Resource Identifier (URI) which will represent the identity of the message within a specific namespace. The creator of the message may choose to associate it with an identity which is specific to the application context within which it is being used, in which case the URN should refer to a namespace which is also application context specific. If no MessageID has been associated with the message then the ESB will assign a unique identifier when it is first sent to a service.
  • RelatesTo: When sending a reply, this represents the unique reference of the message representing the request. This may be used to correlate the response message with the original request.

Service action

The action header is an optional, service-specific URN that may be used to further refine the processing of the message by a service provider or service consumer. The URN should refer to an application-specific namespace.

There are no restrictions on how this header is to be used by the application including, if considered appropriate, ignoring its contents.

 

Time for action – examining the header

Let us modify MyAction to display some of the header information that we need:

  1. Open MyAction and edit the displayMessage method as follows:
  2. public Message displayMessage(Message message) throws Exception {
    System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
    System.out.println("From: " +
    message.getHeader().getCall().getFrom());
    System.out.println("To: " +
    message.getHeader().getCall().getTo());
    System.out.println("MessageID: " +
    message.getHeader().getCall().getMessageID());
    System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
    return message;
    }

  3. Remove the PrintBefore and PrintAfter actions if they exist. Make sure that we have only the BodyPrinter action:
  4. Click on Save.
  5. If the server was still running (and a small red button appears in the console window), then you might notice the application gets redeployed by default.
  6. If this did not happen then deploy the application using the Run menu and select Run As | Run on Server. The following output will be displayed in the console:
  7. INFO [EsbDeployment] Stopping 'Chapter3.esb'
    INFO [EsbDeployment] Destroying 'Chapter3.esb'
    WARN [ServiceMessageCounterLifecycleResource] Calling cleanup on
    existing service message counters for identity ID-7
    INFO [QueueService] Queue[/queue/chapter3_Request_gw] stopped
    INFO [QueueService] Queue[/queue/chapter3_Request_esb] stopped
    INFO [QueueService] Queue[/queue/chapter3_Request_esb] started,
    fullSize=200000, pageSize=2000, downCacheSize=2000
    INFO [QueueService] Queue[/queue/chapter3_Request_gw] started,
    fullSize=200000, pageSize=2000, downCacheSize=2000
    INFO [EsbDeployment] Starting ESB Deployment 'Chapter3.esb'

  8. Run SendJMSMessage.java by clicking Run | Run As | Java Application. The following messages will be printed in the console

  9. INFO [STDOUT] &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
    INFO [STDOUT] From: null
    INFO [STDOUT] To: JMSEpr [ PortReference < <wsa:Address
    jms:localhost:1099#queue/chapter3_Request_esb/>,
    <wsa:ReferenceProperties jbossesb:java.naming.factory.
    initial : org.jnp.interfaces.NamingContextFactory/>,
    <wsa:ReferenceProperties jbossesb:java.naming.provider.url :
    localhost:1099/>, <wsa:ReferenceProperties jbossesb:java.naming.
    factory.url.pkgs : org.jnp.interfaces/>, <wsa:ReferenceProperties
    jbossesb:destination-type : queue/>, <wsa:ReferenceProperties
    jbossesb:destination-name : queue/chapter3_Request_esb/>,
    <wsa:ReferenceProperties jbossesb:specification-version :
    1.1/>, <wsa:ReferenceProperties jbossesb:connection-factory :
    ConnectionFactory/>, <wsa:ReferenceProperties jbossesb:persistent
    : true/>, <wsa:ReferenceProperties jbossesb:acknowledge-mode :
    AUTO_ACKNOWLEDGE/>, <wsa:ReferenceProperties jbossesb:transacted :
    false/>, <wsa:ReferenceProperties jbossesb:type : urn:jboss/esb/
    epr/type/jms/> > ]
    INFO [STDOUT] MessageID: 46e57744-d0ac-4f01-ad78-b1f15a3335d1
    INFO [STDOUT] &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

What just happened?

We examined some of the header contents through the API. We printed the From, To, and the MessageID from within our MyAction class.

Have a go hero – additional header contents

Now modify the MyAction class to print the Action, ReplyTo, RelatesTo, and FaultTo contents of the header to the console.

Here is the listing of the modified MyAction class’s method:

public Message displayMessage(Message message) throws Exception {
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
System.out.println("From: " +
message.getHeader().getCall().getFrom());
System.out.println("To: " +
message.getHeader().getCall().getTo());
System.out.println("MessageID: " +
message.getHeader().getCall().getMessageID());
System.out.println("Action: " +
message.getHeader().getCall().getAction());
System.out.println("FaultTo: " +
message.getHeader().getCall().getFaultTo());
System.out.println("RelatesTo: " +
message.getHeader().getCall().getRelatesTo());
System.out.println("ReplyTo: " +
message.getHeader().getCall().getReplyTo());
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
return message;
}

The context

The message context is used to transport the active contextual information when the message is sent to the target service. This may include information such as the current security context, transactional information, or even context specific to the application. This contextual information is not considered to be part of the service contract and is assumed to change between successive message deliveries.

Where the message context really becomes important is when a service pipeline is invoked through an InVM transport, as this can allow the message to be passed by reference. When the transport passes the message to the target service it will create a copy of the message header and message context, allowing each to be updated in subsequent actions without affecting the invoked service.

Have a go hero – printing message context

Modify the MyAction class to print the context of the ESB message; obtain the context through the getContext() method. You will notice that the context is empty for our sample application as we currently have no security or transactional context attached to the message.

Message validation

The message format within JBoss ESB allows the consumer and producer to use any payload that suits the purpose of the service contract. No constraints are placed on this payload other than the fact that it must be possible to marshall the payload contents so that the messages can be transported between the consumer and producer.

While this ability is useful for creating composite services, it can be a disadvantage when you need to design services that have an abstract contract, hide the details of the implementation, are loosely coupled, and can easily be reused. In order to encourage the loose coupling of services it is often advantageous to choose a payload that does not dictate implementation, for example XML.

JBoss ESB provides support for enforcing the structure of XML payloads for request and response messages, through the XML schema language as defined through the W3C. An XML Schema Document (XSD) is an abstract, structural definition which can be used to formally describe an XML message and guarantee that a specific payload matches that definition through a process called validation.

Enabling validation on a service is simply a matter of providing the schema associated with the request and/or response messages and specifying the validate attribute, as follows:

<actions inXsd="/request.xsd" outXsd="/response.xsd" validate="true">
...
</actions>

This will force the service pipeline to validate the request and response messages against the XSD files, if they are specified, with the request validation occurring before the first service action is executed and the response validation occurring immediately before the response message is sent to the consumer.

If validation of the request or response message does fail then a MessageValidationException fault will be raised and sent to the consumer using the normal fault processing as defined in the MEPs and responses section. This exception can also be seen by enabling DEBUG logging through the mechanism supported by the server.

Have a go hero – enabling validation

Add a request.xsd or a response.xsd or both to your actions in the sample application provided. Enable validation and test the output.

Configuring through the ConfigTree

JBoss ESB handles the majority of its configuration through a hierarchical structure similar to the W3C DOM, namely, org.jboss.soa.esb.helpers.ConfigTree. Each node within the structure contains a name, a reference to the parent node, a set of named attributes, and references to all child nodes.

This structure is used, directly and indirectly, within the implementation of the service pipeline and action processors, and will be required if you are intending to create your own action processors. The only exception to this is when using an annotated action class when the configuring of the action will be handled by the framework instead of programmatically.

Configuring properties in the jboss-esb.xml file

The ConfigTree instance passed to an action processor is a hierarchical representation of the properties as defined within the action definition of the jboss-esb.xml file. Each property defined within an action may be interpreted as a name/value pair or as hierarchical content to be parsed by the action. For example the following:

<action ....>
<!-- name/value property -->
<property name="propertyName" value="propertyValue"/>
<!-- Hierarchical property -->
<property name="propertyName">
<hierarchicalProperty attr="value">
<inner name="myName" random="randomValue"/>
</hierarchicalProperty>
</property>
</action>

This will result in the following ConfigTree structure being passed to the action:

Traversing the ConfigTree hierarchy

Traversing the hierarchy is simply a matter of using the following methods to obtain access to the parent or child nodes:

public ConfigTree getParent() ;
public ConfigTree[] getAllChildren() ;
public ConfigTree[] getChildren(String name) ;
public ConfigTree getFirstChild(String name) ;

Accessing attributes

Attributes are usually accessed by querying the current ConfigTree instance for the value associated with the required name, using the following methods:

public String getAttribute(String name) ;
public String getAttribute(String name, String defaultValue) ;
public long getLongAttribute(String name, long defaultValue) ;
public float getFloatAttribute(String name, float defaultValue) ;
public boolean getBooleanAttribute(String name, boolean defaultValue)
;
public String getRequiredAttribute(String name) throws
ConfigurationException ;

It is also possible to obtain the number of attributes, names of all the attributes, or the set of key/value pairs using the following methods:

public int attributeCount() ;
public Set<String> getAttributeNames() ;
public List<KeyValuePair> attributesAsList() ;

Time for action – examining configuration properties

Let us add some configuration properties to our MyAction. We will make the & and the number of times it needs to be printed as configurable properties. Follow these steps:

  1. Add two members to the MyAction class:
  2. public String SYMBOL = "&";
    public int COUNT = 48;

  3. Modify the constructor as follows:
  4. _config = config;
    String symbol = _config.getAttribute("symbol");
    if (symbol != null) {
    SYMBOL = symbol;
    }
    String count = _config.getAttribute("count");
    if (count != null) {
    COUNT = Integer.parseInt(count);
    }

  5. Add a printLine() method:
  6. private void printLine() {
    StringBuffer line = new StringBuffer(COUNT);
    for (int i = 0; i < COUNT; i++) {
    line.append(SYMBOL);
    }
    System.out.println(line);
    }

  7. Modify the printMessage() method as shown in the following snippet:
  8. printLine();
    System.out.println("Body: " + message.getBody().get());
    printLine();
    return message;

  9. Edit the jboss-esb.xml file and select the action, BodyPrinter. Add two properties symbol as * and count as 50:
  10. Click on Save or press Ctrl + S.
  11. Deploy the application using the Run menu and select Run As | Run on Server.
  12. Run SendJMSMessage.java by clicking Run, select Run As and Java Application.
  13. INFO [STDOUT] **************************************************
    INFO [STDOUT] Body: Chapter 3 says Hello!
    INFO [STDOUT] **************************************************

What just happened?

You just added two properties to the MyAction class. You also retrieved these properties from the ConfigTree and used them.

Have a go hero – additional header contents

Experiment with the other API methods. Write hierarchicalProperty and see how that can be retrieved.

LEAVE A REPLY

Please enter your comment!
Please enter your name here