1. User Guide

User guide is all about things that should be followed and be familiar with as a user or developer of the the UltraESB. UltraESB is easy to use and configure, and this guide walks through the necessary steps in using UltraESB to develop and test your integration solution.

This chapter of the documentation covers the following areas for the user to easily, correctly and effectively develop his/her optimal integration solution.

Use of IntelliJ IDEA Community Edition
Through out this chapter all the development, testing and debugging is being explained using the IntelliJ IDEA Community Edition. It should mostly be the same with other supported IDEs too.

After following this chapter, user should be able to develop his/her integration solution with ease, just like how you write a simple Java program as an standalone application.

1.1. Setting up the IDE

UltraESB is an ESB with seamless IDE integration, facilitating development, running/testing and debugging of the mediation flows within the IDE itself to improve the development life-cycle of your integration project.

Usage of IDE reduces the development time and improves the quality
Usage of the IDE reduces the UltraESB mediation solution development time drastically. It speeds up and improve the quality of all the 3 faces of the life-cycle;
1. Development - Auto completion and context sensitive information guides you develop the solution faster
2. Running/Testing - No need to build and deploy, you can run the solution that you just coded within the IDE, just like a standalone application and test it
3. Debugging - Just debug instead of running and step through within the IDE to find the cause of the problem or to evaluate any expressions

UltraESB supports all 3 major Development Environments and the following sections will discuss setting up the respective IDE to develop, run and debug UltraESB.

At the end of this section, you have mastered the IDE of your interest to develop, run and debug the UltraESB mediation flows.

1.1.1. Setting up IntelliJ IDEA

This guide introduces the user to the UltraESB configuration, testing and debugging with the IntelliJ IDEA Community Edition, which is an excellent IDE now available free of charge - which offers intelligent editing of the configuration as well as editing of Java code fragments embedded within the XML configuration elements.

The UltraESB distribution ships with an IntelliJ IDEA project that allows one to edit the configuration, write custom mediation code, test mediation and services, and debug everything from within the excellent and user friendly IDE environment. You could easily create a similar project for your favourite IDE, and share it with AdroitLogic for inclusion into future releases. Opening the UltraRuntime project at the UltraESB home directory, one could now start to edit the configuration as shown below from within the IDE.

The very first time IDEA opens up the configuration file, it may report that the schema URI’s are not registered as shown below.

register schema uri

Hovering the mouse over the highlighted text will show a balloon to the left edge of that line, which when clicked will show a menu to "Fetch External Resource". You will need to be connected to the Internet, and once you fetch all highlighted schemas you are all set to use the smart schema aware editing features of the IDE.

fetch resource

Note that as the UltraESB configuration is a Spring XML configuration file, a Spring aware version of IntelliJ IDEA (i.e. the commercial version) or another IDE that supports intelligent editing of a Spring configuration will be able to prompt with the valid options for configuration of the Spring managed beans as shown below. This applies when configuring the transports, transaction and JNDI settings etc.

spring aware

When editing the mediation aspects of the UltraESB (e.g. ultra-unit.xml of a deployment unit), any schema aware IDE or editor will now be able to prompt the possible and valid options as per the public schema, and report any violations etc. as shown below. Note that the community edition of the IntelliJ IDEA IDE includes this support.

schema aware

The IntelliJ IDEA IDE community edition also has support for language injection, which could be used to edit Java mediation fragments within the XML configuration.

To enable this feature, open "Settings" and select "Language Injection" from under "Project Settings" (on IDEA 10.x and earlier versions this is available under "IDE Settings"), and add a new language injection for the XML element from the context menu as shown below.

Note
Before you start working with language injections, make sure that IntelliLang plugin is enabled.
language injection xml

You will need to specify the following text as the prefix, and then specify the string "}}" as the suffix to allow us to just write a Java code fragment without writing a full Java class within the configuration.

Prefix

import org.adroitlogic.ultraesb.api.*;
class x {
    private static final org.slf4j.Logger logger = org.slf4j.Logger.getLogger("sequence");
    public void execute(Message msg, Mediation mediation) throws Exception {

Suffix

}}

The prefix will also import the public API and expose the current message as a variable named "msg". The IDE will not inject this prefix or suffix into the configuration, but the user must ensure that any code fragment is a valid xs:string schema data type. Its always suggested to wrap code fragments within "<![CDATA[" and "]]>" tags to ensure that the content is properly handled by the XML parser.

Then fill the "XML Tag" section with local name "java" under the namespace "http://www.adroitlogic.org/ultraesb" as shown below.

Filling xml tag

Once the language injection is configured, the IDE will allow one to edit the Java code fragments within the XML configuration with full IDE support as shown below.

using language injection

The UltraRuntime project ships with a configuration to start the UltraESB from within the IDE both in normal execution mode, and in debug mode. The same would be easily possible with any other IDE. This allows one to edit the configuration, run and debug the configuration all from within the same IDE environment.

run debug

If you see the following red coloured (X) sign in the runtime configuration as shown below marked as (1), that means the JDK is not configured properly for the project.

jdkerror

If this is the case, you need to configure the JDK for your project. For that matter, click on the Project Structure as shown by (2) or press the short cut key combination Ctrl+Alt+Shift+S to edit the project structure.

project structure

Specify a new JDK following the steps;

  1. Click on the Modules under Project Settings from the left most column to select the "UltraRuntime" module settings

  2. Select the Dependencies tab

  3. Click on the New button to define a new JDK as the Module SDK.

You will be able to see the following options drop down and select the JSDK for the module SDK.

jsdk setup

Now you will be able to see the following screen to setup the JSDK as follows.

select jdk

Select the JDK installation directory and click OK as shown in the actions (1) and (2). Click OK for all the open windows to confirm your action to setup the JDK properly.

Setting up support for JSR 223 Scripting Languages - e.g. Groovy

The IntelliJ IDEA CE has built-in support for Groovy. To enable auto completion and full IDE support, first download Groovy and setup the IDEA project to use / support Groovy. In your Groovy script used for mediation, include the following snippet at the top

Groovy header

import org.adroitlogic.ultraesb.api.Mediation import org.slf4j.Logger import org.adroitlogic.ultraesb.api.Message Mediation mediation = mediation; Message msg = message; Logger logger = logger;

The IDE will support autocompletion and other advanced options now as follows

groovy inline

Congratulations!! You and your IDE is now ready to start the development, running, testing and debugging of your UltraESB integration solution!

1.1.2. Setting up Eclipse

This guide describes the steps taken to setup the Eclipse IDE to configure, run/test and debug UltraESB mediation solutions. We have used the "Eclipse IDE for Java EE Developers" release Kepler (4.3) for this exercise.

To get started with, start the Eclipse IDE and open an existing workspace or select a new workspace (e.g. C:\Users\asankha\workspace). If you are already on the Eclipse Workbench, select File → Switch workspace and select the workspace or select "Other" to specify a new workspace.

Selection 002

Select File → Import and from the pop-up window, select General → Existing Projects into Workspace, and specify the path to the UltraESB installation (e.g. C:\With Space\ultraesb-2.0.0)

Selection 003

You may now see 2 Problems reported against the project for its Java Build Path. This is due to a known issue with Eclipse, as the path to the tools.jar of the JDK cannot be detected automatically [MECLIPSE-253].

Selection 004

Right click the error line "Unbounded classpath variable 'JAVA_HOME' …" and select 'Quick Fix' from the popup menu. Press the 'Finish' button.

Workspace202 008

Then from the 'Libraries' tab, select 'JAVA_HOME' and press 'Edit', next select 'Variable' from the 'Edit classpath variable entry' and define a new variable 'JAVA_HOME' pointing to the JDK home (e.g. C:/Java JDK/jdk1.6.0_45). Confirm request for a full build, and the Problems would disappear from Eclipse.

Workspace202 009

Run configurations are automatically created for Eclipse for the following:

  • UltraESB - default configuration

  • UltraESB Sample - edit sample configuration as required

  • UConsole

  • UTerm

  • SOA ToolBox

The above Run configurations can be found under 'Java application' category for 'Run configurations' and could be used to run / debug each of the above from within the Eclipse IDE.

To create a Run configuration to run or debug the UltraESB from within the Eclipse IDE, go to Run → Run Configurations. Create a new 'Java Application' configuration selecting the project as 'UltraRuntime' and the main class as 'org.adroitlogic.ultraesb.UltraServer'. Specify '–confDir=conf' as program arguments, and '-Djava.endorsed.dirs=lib/endorsed' as VM arguments. This creates an Eclipse run configuration to start/debug the default UltraESB configuration as defined in the conf/ultra-root.xml and conf/ultra-dynamic.xml.

To configure specific samples to be run from within Eclipse, select the run configuration 'UltraESB Sample' and edit its 'Arguments' to pass the required configuration file from the samples. (e.g. –confDir=conf –rootConf=samples/conf/ultra-sample-101.xml)

To run any of the unit tests supplied, select the test case and run as a JUnit test case

Note
To setup XML file editing with schema based auto-completion etc, refer to standard Eclipse documentation and extensions. For information on setting up Eclipse for use with Groovy or other JSR 223 scripting languages, refer to this forum post.

Congratulations!! You and your IDE is now ready to start the development, running, testing and debugging of your UltraESB integration solution!

1.1.3. Setting up NetBeans

This guide describes the steps to be taken to setup the NetBeans IDE to configure, run/test and debug UltraESB mediation solutions. We have used the NetBeans 6.9.1 for this exercise.

To get started with, start the NetBeans IDE and navigate to File→Open Project

Menu 002

Next, navigate to the UltraESB installation directory where a pre-configured project file exists

Open20Project 003

NetBeans will then scan the project folder and open the project on the IDE. If you see a warning "Reference Problems" - ignore it. Once the project opens, you could switch to the "Files" view from the left navigation panel, and then select the conf/ultra-dynamic.xml for example to edit. Notice that the UltraESB schema will be automatically retrieved, and auto-completion support will be enabled. (e.g. type "<u:" above the <u:inDestination> element)

sample edit

To debug/run the default configuration, un-comment the inSequence definition in the ultra-dynamic.xml to read as follows:

<u:inSequence>
    <u:class name="sample.SimpleJavaMediation1"/>
</u:inSequence>

Next navigate to UltraRuntime/conf/mediation/src/java/sample/SampleMediation1, and place a break-point at the System.out.println() line of the execute() method

edit java

You could not debug the default configuration named as "UltraESB". To debug a sample configuration, customize the "UltraESB Sample" profile

debugging

If you use the ToolBox to start the sample Jetty Server, and issue a HTTP request using prefix #1, you would endup in the debugging view at the breakpoint

debugging

Note that you can evaluate variables and perform other typical debugger tasks while the message is live within the ESB

To debug a sample configuration, customize the "UltraESB Sample" profile as follows, and specify the sample configuration file. The line would read as follows by default:

--confDir=conf --rootConf=samples/conf/ultra-sample-101.xml

To run/debug sample 201, you should update the –rootConf parameter accordingly.

sample config
JSR 223 scripting language setup
For information on setting up NetBeans for use with Groovy or other JSR 223 scripting languages, refer to the NetBeans documentation.

Congratulations!! You and your IDE is now ready to start the development, running, testing and debugging of your UltraESB integration solution!

1.2. Solution Development

This section describes everything that a developer of UltraESB has to know in the development phase of the integration solution implementation. This section assumes the IDE that you are familiar with being setup and ready to be used in the development process as described in the Setting up the IDE section.

While most of the configurations are mainly done at the ultra-unit.xml file (a spring configuration file additionally supporting the UltraESB schema) of the deployment unit that you are planning to use for this solution. Lets assume we use a deployment unit named "hello-world" which resides in the ULTRA_HOME/conf/deployments/hello-world directory. So you may use any text editor if you are familiar with the configurations for development, but using an configured IDE helps you develop faster and enables you to test and fix issues pretty fast in the development phase.

How ever, depending on your integration requirements you might have to configure the ESB in such a way that it provides you certain transports, such as file or jms and the other deployment related configurations such as clustering, caching etc.. which are configured with the ultra-root.xml spring configuration resides in the ULTRA_HOME/conf directory.

Multiple deployment units and configuration files are supported
Multiple deployment units are inherently supported by the UltraESB from 2.0.0 onwards, how ever if you need the configuration of a single deployment unit to be broken into several files, you may do that by using the spring include mechanism using the ultra-unit.xml configuration file of that deployment unit. How ever for a deployment unit it is a must to have an ultra-unit.xml file.

The development of the integration solution with UltraESB must start with a proxy service, which is the only entry point for the external messages into the UltraESB. Once you have the entry point configured, you may define the exit point/s for the messages that are coming in through the proxy service entry point. Finally the rest is connecting these two points with your mediation logic as shown in the following diagram.

solution dev

So in effect the development process can be broken down to 3 steps as follows.

  1. Entry point configuration with the Proxy Service Configuration

  2. Exit point configuration with the Endpoint/Destination Configuration

  3. Wiring the above 2 points with the Sequence and Mediation Development

Multiple proxy services in a single deployment unit
Deployment unit is just a logical grouping of configuration fragments, used for modularizing the management tasks such as updates etc.. and it is designed to support multiple proxy services. So yes, a deployment unit can have any number of proxy services.

In addition to that, the solution might require new transport configurations too and you may refer to the Configuration and Administration for enabling/configuring transports for the UltraESB.

Once you have the solution implemented with these 3 steps, you can Test and Debug the solution.

1.2.1. Proxy Service Configuration

This section discusses how to configure a proxy service in the UltraESB using the IDE of your interest. This section doesn’t cover the internal behaviour of the proxy services, the proxy service internal action and the architecture of the proxy services are discussed in the Proxy Services under the Architecture and Design of the UltraESB. To understand how proxy services fits into the UltraESB please follow the Overall architecture of the UltraESB.

Proxy Service

Proxy Service is the one and only entry point for the external messages coming into the UltraESB. The concept of proxy service has been designed to make it easy to configure entry points to any integration solution. The unified model of entry points with proxy services enables the configuration to be easily readable and manageable.

Proxy services are configured as XML fragments in the ultra-unit.xml file of a deployment unit which resides in the ULTRA_HOME/conf/deployments directory. A proxy service configuration has been defined by the UltraESB schema and is having the local element name "proxy" qualified with the UltraESB namespace, which is ":http//www.adroitlogic.org/ultraesb".

Proxy services define the transports on which the entry point described by it is exposed, in other words transports on which the proxy service can receive messages. In general proxy services are transport configuration agnostic, except for the name of the transports on which it is deployed. However it can provide information about the entry point to the transport via properties for the transport to expose those entry points properly.

Development of Proxy Services

In order to develop proxy services open the UltraRuntime project shipped with the UltraESB in the installation home directory. Follow the instructions on Setting up the IDE to make sure that the IDE is aware of the schema and to configure the project correctly.

Once the project is loaded, expand the project structure, conf directory and the deployments directory. Create a directory name "hello-world" there to represent a deployment unit and add a file named  ultra-unit.xml to that folder.

ultra unit

Now place the following code fragment which is the wrapping element for a deployment unit configuration which also is a spring configuration.

Bare deployment unit configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:u="http://www.adroitlogic.org/ultraesb"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.adroitlogic.org/ultraesb http://schemas.ultraesb.org/ultraesb-2.0.xsd">

<!-- Add your proxy service configurations here -->

</beans>

Adding a proxy service to the UltraESB is just a matter of adding a proxy element to this configuration file, which creates an entry point for the external messages.

Creating a bare Proxy Service

Since we have already configured the IDE to be UltraESB namespace aware, which qualifies the proxy element, the IDE will give the context sensitive element pallet for us to create the XML configuration for a proxy service. Type the XML starting element tag to see the context menu with the possible options, where you can find the proxy element as follows;

context sensitive editing

Move the down cursor to select the proxy element and hit enter to add it to the configuration file. This will result in a bare proxy configuration to be created with a blank "id" attribute and a "target" element, both of which are mandatory for a proxy service as follows.

Starting proxy service confiuration

<u:proxy id="">
  <u:target></u:target>
</u:proxy>

Specify the proxy service identifier, which can be any string without spaces or other special characters in XML. Lets use the identifier "MyFirstProxy" for the proxy service that we have just created. Giving it an identifier completes the bare proxy service creation. Even though the entry point is there (and UltraESB instance can start with this bare proxy configuration), it doesn’t define any action for the messages coming in via this entry point, or any transports for the entry point to be exposed and hence this proxy service is still not practically usable.

Completing this proxy service to define an integration solution requires the endpoint and sequence wiring to this proxy service, which is done by associating them to the target element. While configuration of endpoints and sequences are discussed in detail under the next two sections on Endpoint/Destination Configuration and Sequence and Mediation Development, the following sub section on Target Configuration walks through the association of the endpoints and sequences to the proxy service and how it is configured.

The other factor for exposing this proxy service is the configuration of the transports on which it is exposed, which will be discussed in the below sub section under Transport Configuration.

Target Configuration

Target configuration is a mandatory element for a proxy service, and hence the IDE will automatically add the element with the tag name "target" with the UltraESB namespace under the proxy element as seen in the above section. One and only one target configuration per proxy service is allowed since it defines all the targets of the proxy service, if you add another target element, the IDE will highlight it giving an error that the child element configurations are wrong.

Target defines the following sub configurations for the proxy service.

  1. In Sequence - defines the mediation for the incoming message to the proxy service

  2. In Destination - defines the destination to deliver the incoming message after the mediation defined by in sequence

  3. Out Sequence - defines the mediation for the out going (response) message

  4. Out Destination - defines the destination for the response message going out from the proxy service

  5. Error Sequence - defines the mediation for any error conditions while processing the message

All of these can either be in-lined or referred from the target configuration of the proxy service.

If you insert a space inside the starting tag of of the target element trying to define an attribute for the target element the IDE will pops-up the following options which are the attribute names that you can use in referring to a sequence or an endpoint already defined in the UltraESB configuration.

target referred

On the other hand if you try to insert a new element into the target element with typing the "<" angular bracket to start an element within the start and closing tags of the target element, the IDE again pops-up the possible elements that can come inside the target element as follows, which are going to either have an in-lined sequence of endpoint as there immediate child elements.

target inline

While these IDE pop-ups helps you to add these elements or attributes without spelling mistakes etc, it is vice to have a clear understanding of the configurations behind all thee.

Mix and match the in-lined and referred content
You can mix referred and in-lined content in defining the target configuration, for example, you can refer to an in sequence defined in the UltraESB while specifying the in destination in-line in the proxy service, you should be careful to not to add the same configuration both as an in-lined element as well as an referred attribute.

In Sequence

In sequence defines the mediation sequence for the incoming messages to the associated proxy service. It can either be referred or specified in-line in the target element. If it is referred the sequence has to be defined in the UltraESB configuration, or if it is in-lined it has to be defined within the in sequence element, as one of the sequence types described in the Sequence and Mediation Development.

To configure a referred in sequence the configuration should be as follows.

Referred in sequence for proxy

<u:proxy id="MyFirstProxy">
  <u:target inSequence="MyInSequence"/>
</u:proxy>

Here the referred sequence has to be defined in the ultra-dynamic.xml or in the ultra-custom.xml as a sequence with the identifier "MyInSequence".

To configure an in-lined in sequence for the proxy target element, the configuration should be as follows.

In-line in sequence for proxy

<u:proxy id="MyFirstProxy">
  <u:target>
    <u:inSequence>
      <!-- Sequence definition -->
    </u:inSequence>
  </u:target>
</u:proxy>

Here the inSequence element should define the mediation sequence with one of the sequence type configurations described on Sequence and Mediation Development. Note that in the in-lined in sequence configuration the element tag name "sequence" has been replaced with the tag name "inSequence".

In Destination

In destination defines the destination for the incoming messages going out via the associated proxy service, after mediated with the in sequence. It can either be referred or specified in-line in the target element. If it is referred the endpoint has to be defined in the UltraESB configuration, or if it is in-lined it has to be defined within the in destination element, as one of the endpoint types described in the Endpoint or Destination Configuration.

To configure a referred in destination the configuration should be as follows.

Referred in destination for proxy

<u:proxy id="MyFirstProxy">
  <u:target inDestination="MyInDestination"/>
</u:proxy>

Here the referred endpoint has to be defined in the ultra-dynamic.xml or in the ultra-custom.xml as an endpoint with the identifier "MyInDestination".

To configure an in-lined in destination for the proxy target element, the configuration should be as follows.

In-line in destination for proxy

<u:proxy id="MyFirstProxy">
  <u:target>
    <u:inDestination>
      <!-- Endpoint definition -->
    </u:inDestination>
  </u:target>
</u:proxy>

Here the inDestination element should define the endpoint with one of the endpoint type configurations described on Endpoint or Destination Configuration. Note that in the in-lined in destination configuration the element tag name "endpoint" has been replaced with the tag name "inDestination".

Out Sequence

Out sequence defines the mediation sequence for the outgoing response messages from the associated proxy service. It can either be referred or specified in-line in the target element. If it is referred the sequence has to be defined in the UltraESB configuration, or if it is in-lined it has to be defined within the out sequence element, as one of the sequence types described in the Sequence and Mediation Development.

To configure a referred out sequence the configuration should be as follows.

Referred out sequence for proxy

<u:proxy id="MyFirstProxy">
  <u:target outSequence="MyOutSequence"/>
</u:proxy>

Here the referred sequence has to be defined in the ultra-dynamic.xml or in the ultra-custom.xml as a sequence with the identifier "MyOutSequence".

To configure an in-lined out sequence for the proxy target element, the configuration should be as follows.

In-line out sequence for proxy

<u:proxy id="MyFirstProxy">
  <u:target>
    <u:outSequence>
      <!-- Sequence definition -->
    </u:outSequence>
  </u:target>
</u:proxy>

Here the outSequence element should define the mediation sequence with one of the sequence type configurations described on Sequence and Mediation Development. Note that in the in-lined out sequence configuration the element tag name "sequence" is replaced with the tag name "outSequence".

Out Destination

Out destination defines the destination for the outgoing response messages going out via the associated proxy service, after mediated with the out sequence. It can either be referred or specified in-line in the target element. If it is referred the endpoint has to be defined in the UltraESB configuration, or if it is in-lined it has to be defined within the out destination element, as one of the endpoint types described in the Endpoint or Destination Configuration.

To configure a referred out destination the configuration should be as follows.

Referred out destination for proxy

<u:proxy id="MyFirstProxy">
  <u:target outDestination="MyOutDestination"/>
</u:proxy>

Here the referred endpoint has to be defined in the ultra-dynamic.xml or in the ultra-custom.xml as an endpoint with the identifier "MyOutDestination".

To configure an in-lined out destination for the proxy target element, the configuration should be as follows.

In-line out destination for proxy

<u:proxy id="MyFirstProxy">
  <u:target>
    <u:outDestination>
      <!-- Endpoint definition -->
    </u:outDestination>
  </u:target>
</u:proxy>

Here the outDestination element should define the endpoint with one of the endpoint type configurations described on Endpoint or Destination Configuration. Note that in the in-lined out destination configuration the element tag name "endpoint" is replaced with the tag name "outDestination".

Error Sequence

Error sequence defines the mediation sequence for the messages that faces an error condition while processing in the associated proxy service. It can either be referred or specified in-line in the target element. If it is referred the sequence has to be defined in the UltraESB configuration, or if it is in-lined it has to be defined within the error sequence element, as one of the sequence types described in the Sequence and Mediation Development.

To configure a referred error sequence the configuration should be as follows.

Referred error sequence for proxy

<u:proxy id="MyFirstProxy">
  <u:target errorSequence="MyErrorSequence"/>
</u:proxy>

Here the referred sequence has to be defined in the ultra-dynamic.xml or in the ultra-custom.xml as a sequence with the identifier "MyErrorSequence".

To configure an in-lined error sequence for the proxy target element, the configuration should be as follows.

In-line error sequence for proxy

<u:proxy id="MyFirstProxy">
  <u:target>
    <u:errorSequence>
      <!-- Sequence definition -->
    </u:errorSequence>
  </u:target>
</u:proxy>

Here the errorSequence element should define the mediation sequence with one of the sequence type configurations described on Sequence and Mediation Development. Note that in the in-lined error sequence configuration the element tag name "sequence" is replaced with the tag name "errorSequence".

Referred sequences/endpoitns enables reusability
Note that, while the sequences and endpoints defined in-line in a proxy service target are not reusable in another proxy service, the referred sequences and endpoints allows the same reference to be used for another proxy service as either in, out, error sequence or in, out destination.
Transport Configuration

For any proxy service to be reachable over a given transport, the proxy configuration should define the transport on which it is exposed. Optionally any configuration properties associated with that transport for registering the service should be passed in as transport configuration properties in the proxy service.

The transport configuration of a proxy service is specified with element tag named "transport" again qualified with the UltraESB namespace. Unlike in the case of the target element, this transport element can/should repeat for each and every transport on which this service is exposed. In other words, the configuration should have exactly the same number of transport elements defining the transports on which this proxy service is exposed. The configuration should specify the transport identifier, in the "id" attribute of the transport element.

Transport identifier
UltraESB transports are defined in the ultra-root.xml file again found on the same folder as the ultra-dynamic.xml file, which is the conf directory. Open the ultra-root.xml and find the spring bean identifier of the transport listener that you want to configure the proxy service, for example the default spring bean id for the HTTP transport is, "http-8280". See more information on transport configuration under the Configuration and Administration.

Define the transports over which the proxy service is exposed, as shown in the following example;

Transport configuration for proxy

<u:proxy id="MyFirstProxy">
  <u:transport id="http-8280"/>
  <u:target></u:target>
</u:proxy>

Certain transports have transport specific configurations to be done at the proxy service level and those are specified as transport properties in the configuration with the element tag name "property" within the transport element. Information on different transport properties could be found in the Transport configuration properties reference guide.

Advance Proxy Service Configurations

While the bare proxy configuration is pretty easy and straight forward, it’s flexibility to define advance properties or qualities of the entry point are very convenient in a practical integration solutions. There are many advance configurations including the service properties, pinned servers and work manager configuration etc..

Pinned Servers Configuration

Pinned servers is a concept where you can limit the operation of a particular proxy service into a given node or a set of nodes in a clustered deployment of the UltraESB, when sharing the same configuration. The concept found to be very convenient when exposing the proxy service on polling transports (file transport and email transport, etc..) in a clustered deployment, to make sure the same message (file or email) is not tried to be pulled by different nodes in the cluster.

Once configured to be pinned (which is an optional configuration) the proxy service will look at the node identifier (passed in as serverName for the startup script) and check whether it matches an entry in the pinned servers list before starting the proxy. If not the proxy service will not be operational on that node of the cluster.

To configure pinned servers for a proxy service add the attribute "pinnedServers" to the proxy element defining the proxy service and specify the node identifiers (server names) in the cluster, on which this service needs to be exposed.

Pinning the proxy for transports

<u:proxy id="MyFirstProxy" pinnedServers="esb1, esb2">
  <u:transport id="http-8280"/>
  <u:target></u:target>
</u:proxy>

The above configuration limits the proxy service to be only operational in nodes identified as esb1 and esb2.

Note
A cluster in this case has the identical configuration, even though some proxy services are pinned to certain nodes and those proxy services are not operational on the other nodes in the cluster, in other wards are pinned to the given nodes only.

In case of a failure of a node with pinned server if any backup node is specified for that node, it will automatically take over the failed node and start acting as that node, after a configurable grace period. Upon seeing the original failed node joining back into the cluster the failover node stops acting as the failed node and stops acting as that node. Follow the Clustering Configuration on the Configuration and Administration for more information on failover node configuration.

Pinned server concept on non-clustered setup
You could use the pinned servers on a non clustered deployment too, in which case the above automatic failover node will not be effective. However, UTerm provides a terminal command to manually start/stop acting as a given node identifier, which is operational on clustered as well as on non-clustered deployments.

Pinned servers is an advance configuration for proxy services which helps you define the maximum number of operational proxy services instance in the cluster regardless of the number of nodes in the cluster. For example, in the previous configuration, it is guaranteed that only 2 operational proxy service instances of MyFirstProxy is there on the complete cluster.

Work Manager Configuration

Work manager is a concept derived from the Java thread pool executors, where you can have two thread pools named primary and secondary, with work being overflowed to the secondary when the primary pool gets exhausted. You may go through the Static Configurations of the UltraESB under the overall architecture to understand the concepts of a work manager in detail.

Work Managers are defined in the ultra-root.xml spring configuration located on the same directory as the ultra-dynamic.xml file. The configuration of the work manager for a proxy service is optional and if specified, makes sure that the proxy service is always using the named work manger to submit messages for processing, which defaults (if no work manager is specified in the proxy service) to the work manager identified with the "default" key.

To configure a work manager, use the "workManager" attribute of the proxy element to specify the work manager identifier.

Custom work manger for proxy

<u:proxy id="MyFirstProxy" workManager="myCustomWM">
  <u:transport id="http-8280"/>
  <u:target></u:target>
</u:proxy>

Here the "myCustomWM" is the identifier of the spring bean defining a work manger in the ultra-root.xml root configuration of the UltraESB.

1.2.2. Endpoint or Destination Configuration

Endpoints (destinations) are the configuration describing an external EPR that can be used to send messages from UltraESB. The endpoint configuration also defines the qualities and properties of an EPR. While this section concentrates on the configuration aspect of the endpoints, for advance endpoint configurations, it is good/recommended to cover the concepts from Understanding Endpoints or Destinations under the Architecture and Design of UltraESB.

Endpoint Configuration

There is a slight difference in defining a reusable endpoint on the configuration and defining an endpoint in-line in a proxy service, either as it’s in destination or out destination. The difference is mainly in the root element tag name. If you are defining a reusable endpoint the tag name to be used is "endpoint" while the same changes to "inDestination" if you in-line it as an in destination of a proxy service, or to "outDestination" if you in-line it as an out destination of a proxy service. Except for that the configuration should be identical whether you in-line it or defined as a reusable endpoint.

To add a reusable endpoint into the configuration open up the "ultra-unit.xml" file of the deployment unit that you want to add this endpoint, in your IDE and start to insert an XML element with the angular bracket ("<"), upon which the IDE will pop you up the following options.

endpoint add

Select the "u:endpoint" as shown above and hit enter to add an endpoint. The endpoint with a bare configuration will be added as follows;

Starting the reusable endpoint configuration

<u:endpoint id="">
  <u:address></u:address>
</u:endpoint>

Note the automatic addition of the mandatory "id" attribute, which is the identifier of the endpoint you can use as the value for either an inDestination attribute or outDestination attribute of the target element of a proxy service. Apart from that it automatically adds a child element with the element tag name "address", again qualified with the UltraESB namespace.

Identifier for a reusable endpoint must be given and lets use the "MyFirstEndpoint" identifier for that matter. The next thing is the selection of the endpoint type, which is specified as an attribute to the endpoint element. Having the idea of adding this attribute press space at the end of the id attribute declaration within the endpoint element, where you will be able to see the following options.

ep attributes

While we will discuss the "keepalive" and "timeout" attributes under the Advance Configurations of endpoints, our intention here is to define the endpoint type. Select the "type" attribute to define the endpoint type.

Giving an endpoint an identifier

<u:endpoint id="MyFirstEndpoint" type="">
  <u:address></u:address>
</u:endpoint>
Endpoint Types

There are 8 types of endpoints in UltraESB categorized according to the behaviour of the endpoint. To select the exact type you want you might want to go through the concepts behind each and every type of the endpoint described under the Architecture and Design.

Coming back to configuration, you can select the value for the type attribute added previously to configure different endpoint types. The IDE will help us figure out the configuration for our type attribute value, if you press Ctrl+Space while the cursor is in between the (") double quote characters to define the attribute value.

ep types

Select the type that you desire and configure the rest according to the type you have selected as described below under relevant type configuration.

Single Endpoints

Single endpoint as it’s name depicts can have exactly one address as its address. Refer to single endpoint concepts for more information on it.

Configuration of the single endpoint requires the endpoint type attribute to be set to "single" and it should include an address of any valid address type as follows.

Single address endpoint configuration

<u:endpoint id="MyFirstEndpoint" type="single">
  <u:address>http://localhost:9000/service/EchoService</u:address>
</u:endpoint>

Single endpoints are treated as the default endpoint type, so any endpoint without the type attribute is also treated as a single endpoint.

Default endpoint type
Single endpoint is the default endpoint type and hence the type declaration for single endpoints are optional.
Round-Robin Endpoints

Round-robin endpoint should have more than one address and there is no upper bound to the number of addresses. It deliver messages to the defined addresses in a round robin fashion balancing the load yet without doing fail-over. Refer to round-robin endpoint concepts for more information.

Configuration of the round-robin endpoint requires the endpoint type attribute to be set to "round-robin" and it should include a set of addresses of any valid address type as follows.

Round-Robin load balance endpoint configuration

<u:endpoint id="MyFirstEndpoint" type="round-robin">
  <u:address>http://localhost:9000/service/EchoService</u:address>
  <u:address>http://localhost:9001/service/EchoService</u:address>
  <u:address>http://localhost:9002/service/EchoService</u:address>
</u:endpoint>

In general all the addresses refer to the same replicated service.

Fail-over Endpoints

Fail-over endpoint should have more than one address and there is no upper bound to the number of addresses. It deliver messages to the first endpoint among the defined addresses, and if it fails tries the next defined address providing failover. Refer to failover endpoint concepts for more information.

Configuration of the fail-over endpoint requires the endpoint type attribute to be set to "fail-over" and it should include a set of addresses of any valid address type as follows.

Failover endpoint configuration

<u:endpoint id="MyFirstEndpoint" type="fail-over">
  <u:address>http://localhost:9000/service/EchoService</u:address>
  <u:address>http://localhost:9001/service/EchoService</u:address>
  <u:address>http://localhost:9002/service/EchoService</u:address>
</u:endpoint>

In general all the addresses refer to the same replicated service.

Round-Robin with Fail-over Endpoints

Round-robin with fail-over endpoint should have more than one address and there is no upper bound to the number of addresses. It deliver messages to the defined addresses in a round-robin fashion while providing fail-over, capability, i.e. if an address fails endpoint tries the next available address to send the message. Refer to round-robin with fail-over endpoint concepts for more information.

Configuration of the round-robin with fail-over endpoint requires the endpoint type attribute to be set to "round-robin-with-fail-over" and it should include a set of addresses of any valid address type as follows.

Round-Robin load balance with failover endpoint configuration

<u:endpoint id="MyFirstEndpoint" type="round-robin-with-fail-over">
  <u:address>http://localhost:9000/service/EchoService</u:address>
  <u:address>http://localhost:9001/service/EchoService</u:address>
  <u:address>http://localhost:9002/service/EchoService</u:address>
</u:endpoint>

In general all the addresses refer to the same replicated service.

Weighted Endpoints

Weighted endpoint should have more than one address with a weight associated with each and every address and there is no upper bound to the number of addresses. It deliver messages to the addresses defined considering the weight associated with those addresses balancing the load according to the assigned weight yet without doing fail-over. Refer to weighted endpoint concepts for more information.

Configuration of the weighted endpoint requires the endpoint type attribute to be set to "weighted" and it should include a set of addresses of any valid address type as follows.

Weighted load balance endpoint configuration

<u:endpoint id="MyFirstEndpoint" type="weighted">
  <u:address weight="1">http://localhost:9000/service/EchoService</u:address>
  <u:address weight="1">http://localhost:9001/service/EchoService</u:address>
  <u:address weight="2">http://localhost:9002/service/EchoService</u:address>
  <u:address weight="4">http://localhost:9003/service/EchoService</u:address>
</u:endpoint>

In general all the addresses refer to the same replicated service. Note the "weight" attribute and the integer value assigned as the weight in all addresses.

Weighted with Fail-over Endpoints

Weighted with fail-over endpoint should have more than one address and there is no upper bound to the number of addresses. It deliver messages to the defined addresses according to the weight assigned to each and every address while providing fail-over, capability, i.e. if an address fails endpoint tries the next available address to send the message. Refer to weighted with fail-over endpoint concepts for more information.

Configuration of the weighted with fail-over endpoint requires the endpoint type attribute to be set to "weighted-with-fail-over" and it should include a set of addresses of any valid address type as follows.

Weighted load balance with failover endpoint configuration

<u:endpoint id="MyFirstEndpoint" type="weighted-with-fail-over">
  <u:address weight="1">http://localhost:9000/service/EchoService</u:address>
  <u:address weight="1">http://localhost:9001/service/EchoService</u:address>
  <u:address weight="2">http://localhost:9002/service/EchoService</u:address>
  <u:address weight="4">http://localhost:9003/service/EchoService</u:address>
</u:endpoint>

In general all the addresses refer to the same replicated service.

Random Endpoints

Random endpoint should have more than one address and there is no upper bound to the number of addresses. It deliver messages to to an address selected randomly among the defined addresses balancing the load according to probability of getting selected yet without doing fail-over. Refer to random endpoint concepts for more information.

Configuration of the random endpoint requires the endpoint type attribute to be set to "random" and it should include a set of addresses of any valid address type as follows.

Random load balance endpoint configuration

<u:endpoint id="MyFirstEndpoint" type="random">
  <u:address>http://localhost:9000/service/EchoService</u:address>
  <u:address>http://localhost:9001/service/EchoService</u:address>
  <u:address>http://localhost:9002/service/EchoService</u:address>
</u:endpoint>

In general all the addresses refer to the same replicated service.

Random with Fail-over Endpoints

Random with fail-over endpoint should have more than one address and there is no upper bound to the number of addresses. It deliver messages to an address selected randomly among the set of defined addresses while providing fail-over, capability, i.e. if a selected address fails endpoint tries the next selected address to send the message. Refer to random with fail-over endpoint concepts for more information.

Configuration of the random with fail-over endpoint requires the endpoint type attribute to be set to "random-with-fail-over" and it should include a set of addresses of any valid address type as follows.

Random load balance with failover endpoint configuration

<u:endpoint id="MyFirstEndpoint" type="random-with-fail-over">
  <u:address>http://localhost:9000/service/EchoService</u:address>
  <u:address>http://localhost:9001/service/EchoService</u:address>
  <u:address>http://localhost:9002/service/EchoService</u:address>
</u:endpoint>

In general all the addresses refer to the same replicated service.

Address Configuration

Addresses within an endpoint describes the actual destination or the EPR of an endpoint. Possible configurations for addresses are the address type configuration, address identifier and the weight, which only applies to weighted endpoint addresses.

All these are configured as attributes of the address element, while for some address types the address value is defined in the address element body as text. In order to see the options available for address configuration type space within the address element at the end of the address tag name.

address options

Address identifier is configured with the "id" attribute and the value of this attribute can be any string except for the illegal characters in XML. While the "weight" attribute only applies to weighted endpoint types, the type attribute is discussed as the next section in-detail.

Address Types

There are 4 types of addresses categorized according to the way they are configured. To configure the address type the attribute "type" needs to be added to the address element and the respective type value has to be specified as the attribute value.

To see the valid options for the address types, type Ctrl+Space within the double quotes ("), where you will be able to see the following pop-up value set.

address types
URL Address

This type of addresses are the most common address type and hence is the default address type. To configure an URL address you just need to specify the complete URL of the service to which this endpoint address refers to, as follows. For more information refer to the URL address concepts.

URL (optional) type address configuration

<u:address type="url">http://localhost:9000/service/EchoService</u:address>

Since this type of addresses are the default type if no type is defined the address is considered as URL type.

Default address type
It is optional to specify the type attribute and the attribute for URL type addresses, and hence you can just neglect the type for any URL address
Prefix Address

This type of addresses are mostly used in load balancing and fail-over endpoints to change the prefix of the endpoint address while appending the rest of the URL to the specified new prefix. To configure an prefix address you need to specify the prefix of the address as follows. For more information refer to the prefix address concepts.

Prefix type address configuration

<u:address type="prefix">http://localhost:9000/service</u:address>
Default Address

This type of address is used to send the messages to the endpoint implicitly defined in the message itself, and hence no address value is given in configuring the endpoint. To configure a default type endpoint you just need to specify the endpoint type and the address extraction from the message will be done by the engine. For more information refer to the default endpoint concepts.

Default type address configuration

<u:address type="default"/>
Response Address

This type of addresses are used to send the messages back to the caller as a response, and hence no address value is given in configuring the endpoint. To configure a response type endpoint you just need to specify the endpoint type and the address caller selection from the message will be done by the engine. For more information refer to the response endpoint concepts.

Response type address configuration

<u:address type="response"/>
Error Handing Configuration

Endpoint error handling configuration is a unified across all the endpoint types. Endpoint error handling is designed around the error codes that the engine reports on a failure of an address specified in the endpoint. By analyzing the error code received from the failure the endpoint takes the error handling decisions under 3 categories all configured as child elements of the endpoint element.

Safe to Retry Configuration

On a failure of an endpoint address, it could retry the same message to a different address on the same endpoint if the fail-over is turned on. But for certain failures you might not want to re-try the same message, as it could lead to duplication of messages to the back-end, while some errors are obvious that you can safely retry (for example a connect time out meaning that the ESB failed to establish the connection to the back end). In mission critical systems, it is wise to be able to configure the failure cases which are safe to retry.

All failures in UltraESB are associated with a unique error code and hence this decision to retry or not to retry, is being done by looking at the error code. While you can find the default behaviour and more information on this under fail-over concepts, you also can configure the error codes which are safe to retry, overriding the defaults.

For that matter the configuration would need to add an element with the tag name "safeToRetryErrorCodes" as follows;

Safe to retry configuration of endpoints

<u:endpoint id="MyFirstEndpoint" type="round-robin-with-fail-over">
  <u:address>http://localhost:9000/service/EchoService</u:address>
  <u:address>http://localhost:9001/service/EchoService</u:address>
  <u:safeToRetryErrorCodes>all</u:safeToRetryErrorCodes>
</u:endpoint>

While the above configuration specifies all error codes are safe to re-try, as opposed to the default behaviour, you can configure a sub set of error codes by listing the error codes as a comma separated value set.

Temporary Failure Configuration

Temporary failures are the failures that mark the address as temporarily failed and the endpoint is still available within the given grace period. These temporary failures are detected again based on the error codes and you can find the information on default temporary failure error codes and more information on temporary and suspension failure in the endpoint error handling concepts.

Configuring the temporary failures require an addition of "temporaryFailures" element into the endpoint element, and configuring the grace period and the error codes for marking the address as temporary failed with the child elements "gracePeriod" and "errorCodes" respectively.

Temporary failures configuration of endpoint

<u:endpoint id="MyFirstEndpoint" type="round-robin-with-fail-over">
  <u:address>http://localhost:9000/service/EchoService</u:address>
  <u:address>http://localhost:9001/service/EchoService</u:address>
  <u:safeToRetryErrorCodes>all</u:safeToRetryErrorCodes>
  <u:temporaryFailures>
    <u:gracePeriod>3000</u:gracePeriod>
    <u:errorCodes>101508,101506,101505,101504</u:errorCodes>
  </u:temporaryFailures>
</u:endpoint

Here a subset of the default error codes are specified as the temporary failure error codes.

Suspend on Failure Configuration

Suspension failures are the failures that mark the address as suspended and the address wont be available for the duration in-effect. These suspension failures are also detected based on the error codes and you can find the information on default suspension failure error codes and more information on temporary and suspension failure in the endpoint error handling concepts.

Configuring the suspension on failure require an addition of "suspendOnFailure" element into the endpoint element, and configuring the initial duration, progression factor and the maximum duration with the error code under child elements with names "initialDuration","progressionFactor","maximumDuration" and "errorCodes" respectively.

Suspend on failure configuration of endpoint

<u:endpoint id="MyFirstEndpoint" type="round-robin-with-fail-over">
  <u:address>http://localhost:9000/service/EchoService</u:address>
  <u:address>http://localhost:9001/service/EchoService</u:address>
  <u:safeToRetryErrorCodes>all</u:safeToRetryErrorCodes>
  <u:temporaryFailures>
    <u:gracePeriod>3000</u:gracePeriod>
    <u:errorCodes>101508,101506,101505,101504</u:errorCodes>
  </u:temporaryFailures>
  <u:suspendOnFailure>
    <u:initialDuration>4000</u:initialDuration>
    <u:progressionFactor>1.0</u:progressionFactor>
    <u:maximumDuration>10000</u:maximumDuration>
    <u:errorCodes>101503,101511</u:errorCodes>
  </u:suspendOnFailure>
</u:endpoint>

The duration for which the endpoint is suspended is described with the initial duration (which is the duration for the first suspension), progression factor (which is the factor in which the duration gets increased on consecutive suspension failures after being ready for use) and maximum duration (which is the maximum duration for which the endpoint be suspended).

Advance Endpoint Options

Apart from that, there are few advance options which enables few advance configurations of endpoints and addresses.

Endpoints allow custom properties to be configured at the endpoint level. Some of these properties may be only valid for some types of messages. For example, HTTP authentication properties, email properties (e.g. subject) etc maybe specified at an endpoint level.

Keepalive
Timeout
Response validation

Response validation allows a successfully received message be validated to check if it indicates a successful response, a temporary error or a suspension error, as described in the concept of response validation. Configuring the response validator is being done as a property configuration for the endpoint. Further the response validator instance should be initialized with spring and that bean identifier is user to configure the response validator.

To configure the response validator, add a property with the key "ultra.endpoint.response_validator_bean" and the value being the spring bean identifier of the actual validator instance.

Response validaor configuration of endpoint

<u:endpoint id="MyFirstEndpoint" type="round-robin-with-fail-over">
  <u:address>http://localhost:9000/service/EchoService</u:address>
  <u:address>http://localhost:9001/service/EchoService</u:address>
  <u:property name="ultra.endpoint.response_validator_bean" value="soapValidator"/>
</u:endpoint>

<bean id="soapValidator" class="org.adroitlogic.ultraesb.core.endpoint.SOAPResponseValidator">
  <property name="failOnFaultText" value="Service not available"/>
</bean>
HTTP Location header switching of response

Some responses from the back-end services contain the HTTP Location header in which case the ESB might want to intercept the message and re-write the Location header value, as described in concept of HTTP Location switching. This again is configured as an endpoint property.

To configure the HTTP Location switching, add a property with the key "ultra.endpoint.switch_location_headers_to" with the value of the Location header that you want to switch to.

HTTP location header switching configuration of endpoint

<u:endpoint id="MyFirstEndpoint">
  <u:address>http://localhost:9000/service/EchoService</u:address>
  <u:property name="ultra.endpoint.switch_location_headers_to" value="http://localhost:8280/service/rest-proxy"/>
</u:endpoint>
Note
Completing the endpoint configuration, once again to emphasis on the in-lined endpoints in the proxy services, all the above configurations endpoint tag name has to be replaced with either "inDestination" or "outDestination" depending on the in-lined destination type.

1.2.3. Sequence and Mediation Development

This section discuss the development of sequences and mediation logic to facilitate mediation of the messages coming into the proxy services.

Sequence and Mediation

A Sequence defines the mediation actions to be performed on a message. A Sequence may be defined in-line and locally to a proxy service, or defined as a re-usable sequence with an ID and referenced. A sequence maybe specified as a Java or JSR 223 script fragment, class or Spring bean, or a source file. Irrespective of the style of definition, each sequence executes as byte-code on the JVM.

Java and script sequences are exposed the current message by a special variable "msg", and the Mediation instance by the special variable"mediation". The interfaces Message and Mediation in the UltraESB API package allows one to perform almost anything within a sequence. However, one should be careful to not spawn new threads from within a sequence, as the UltraESB manages the execution threads which invokes sequences.

While the API documentation provides the complete reference of the operations available to use in mediation, the Mediation Reference describes those operations from the usage perspective, where it will be easy to map your requirement usage into the required API call and how to effectively call it.

To configure a sequence you need to add an element with the tag name "sequence" qualified with the UltraESB namespace. On your IDE, type angular bracket ("<") to see the available options on the ultra-unit.xml file of the deployment unit and select the sequence as shown below to add a sequence.

sequence add

Once you select the sequence and hit enter a bare sequence will be added with an "id" attribute. Fill the id attribute with "MyFirstSequence" to give the identifier for the sequence.

Starting the sequence configuration

<u:sequence id="MyFirstSequence">
  <!-- sequence type child element -->
</u:sequence>
Note
While a sequence that is referred is defined on the top level in the ultra-dynamic.xml with the "sequence" element tag name with an identifier an in-lined sequence of a proxy service will have the element tag name "inSequence","outSequence" or "errorSequence" depending on where it is placed in the proxy service.
Sequence Types

The UltraESB allows one to use multiple formats for specifying mediation steps within a sequence. The support ranges from Java code snippets specified as Java source code fragments, to any scripting language supported by JDK 6. All sequences specified as Java or scripting language source code is compiled and executed as byte code. This allows a user with extreme ease of use with his preferred language/s of choice, whilst allowing all code to run at compiled byte code speed with the full power of the JVM. It is also possible to only provide compiled sequences as Java classes, or even specify a Spring managed bean as a sequence. Although leaving mediation logic in configuration allows simpler management and version control, using compiled code may be preferred by certain other users concerned with security etc. and a hardened deployment model for configuration.

Sequence type is identified with the type of the child element used inside the sequence element. Unlike in endpoints there is no attribute defining the type as there are clearly different child elements for each and every sequence type.

To add a sequence type child element again type the angular bracket ("<") within the sequence element (this usually gets popped up just after specifying the identifier for the sequence too) and select the desired type from the popped up list of child elements as per the following description on each and every sequence types.

sequence types
A Java code snippet

A Java code snippet is the most easy way to mediate messages, and usually makes use of the utility methods exposed by the helper class 'Mediation'. Optionally, a snippet could specify any packages used by the code for import.

Sample Java code snippet sequence

<u:java import="java.io.*;"><![CDATA[
  String[][] ns = {{"soap", "http://soap.services.samples/"}};
  if (mediation.filter(msg, "//soap:getQuote/request/symbol", ns, "ADRT")) {
    mediation.sendToEndpoint(msg, "stockquote");
  } else {
    mediation.sendToEndpoint(msg, "stockquote-err");
  }
]]></u:java>
A script snippet sequence

A Script sequence could be written using any scripting language supported by Java JDK 6. A good list of languages maybe found at [https://en.wikipedia.org/wiki/List_of_JVM_languages]. The UltraESB does not ship with optional libraries required to support these scripting languages, and the user is responsible for making these available to the runtime if required. However, the JDK ships with support for Javascript, which is available out of the box with the UltraESB.

Sample script snippet sequence

<u:script><![CDATA[
  var val = message.getMessageProperty("QUERY_STRING");
  val = val.replace('x', 'a');
  val = val.replace('y', 'b');
  val = val.replace('z', 'c');
  message.addMessageProperty("QUERY_STRING", val);
]]></u:script>
A script file

A script file sequence is similar to a script snippet sequence and is defined as follows.

Sample script file sequence

<u:scriptFile filename="test/resources/script_seq.js"/>

Where the file script_seq.js may contain the following

Script file

println("Message target : " + message.getDestinationURL());
if ("gold".equals(message.getFirstTransportHeader("ClientID"))) {
  mediation.sendToEndpoint(message, "test1");
} else {
  mediation.sendToEndpoint(message, "test2");
}
Byte code sequence

A Class that implements the public API interface 'JavaClassSequence' maybe specified as a byte code sequence. A byte code sequence is stateful and may persist information between successive calls as shown in the following example

Sample byte code sequence

<u:class name="org.adroitlogic.ultraesb.core.SampleByteCodeSequence"/>

Where the byte code is the class file compiled from the following source

Class file source of the sample byte code sequence

package org.adroitlogic.ultraesb.core;

import org.adroitlogic.ultraesb.api.JavaClassSequence;
import org.adroitlogic.ultraesb.api.Message;

public class SampleByteCodeSequence implements JavaClassSequence {
  private long startTime;
  private int count;

  public void execute(Message msg, Mediation mediation) throws Exception {
    System.out.println("Message target : " + msg.getDestinationURL());
    if ("gold".equals(msg.getFirstTransportHeader("ClientID"))) {
      org.adroitlogic.ultraesb.TestMediation.sendToEndpoint(msg, "test1", "responseSeqKey");
    } else {
      org.adroitlogic.ultraesb.TestMediation.sendToEndpoint(msg, "test2", "responseSeqKey");
    }
    count++;
  }

  public void init(Configuration config) {
    startTime = System.currentTimeMillis();
  }

  public void destroy() {
    System.out.println("Byte code sequence, Execution time : " + (System.currentTimeMillis() - startTime) +
      "ms. Processed : " + count + " messages");
  }
}
Java source file

It is also possible to specify the source code of a Java class as shown above as a Java source sequence. The UltraESB would simply compile the sequence at each startup.

Sample Java source file sequence

<u:javaFile filename="test/resources/java_seq.java"/>
Spring bean sequence

A Spring bean which implements the 'JavaClassSequence' interface maybe specified as a Spring bean sequence. For such a sequence one may use the Spring configuration to wire its dependencies, and simply inject this instance for mediation as shown in the example below.

Sample spring bean sequence

<u:sequence id="myseq7">
  <u:bean name="mybean"/>
</u:sequence>
...
<bean name="mybean" class="org.adroitlogic.ultraesb.core.SampleByteCodeSequence"/>
Support for other options and languages

The support for script based sequences effectively allows one to define a new language for configuration. Thus if required one can invent a new configuration language as a Java 6 scripting language, and it could even be an XML configuration language - for example.

Error Handling of Sequences

Error handlers for sequences are defined as a reference to another sequence via an attribute in the sequence element. Error handler is getting the message in case of an error while on the mediation of the defined sequence.

Configuring an error handler requires a referred sequence and that should be linked with the attribute named "onErrorInvoke" as follows.

Error handler configuration of sequence

<u:sequence id="MyFirstSequence" onErrorInvoke="MyErrorSequence">
  <!-- sequence definition -->
</u:sequence>

<u:sequence id="MyErrorSequence">
  <!-- error sequence definition -->
</u:sequence>

1.3. Testing and Debugging

This section discusses how you can use the seamless IDE integration of the UltraESB to test, debug and fix the solution that you develop before deploying it on production or even in integration environment. With almost all the other ESBs testing a solution will require you to build the artifact and deploy it on an integration environment to test it. This process leads to a major drawback of the software testing theories. In software engineering, the modern software life-cycle contains 2 phases of testing as follows;

  1. Developer testing (White-Box testing) - to make sure the solution that you develop works at least on the proper flow

  2. Integration testing (Black-Box testing) - to make sure that the solution delivers what it meant to be, on an environment which is nearly equal to that of the target production environment and the testing of the exception flows.

While the integration testing (quality assurance) of-course needs an integration environment and a deployable artifact for testing, the developer testing just need to make sure that the functionality that the developers develop are correct. This is very close to writing unit tests for verifying the functionality that is being developed. This chapter mainly focuses on the developer testing and debugging of the solution within the IDE while the integration testing requires an integration environment and a deployment.

The rest of this documentation selects a sample solution and shows you how to run it within the IDE, test it, debug it and fix the issues if there are any to complete the development phase of the solution.

1.3.1. Sample Solution

The Solution Development section extensively describes how you can develop a solution, for this section we are going to select a sample solution that will help the explanation of the rest of the functionality testing and debugging.

This solution is a simple "hello-world" deployment unit with the configuration which consists of a proxy service, 2 endpoints and 2 sequences. The following code segments shows the ultra-unit.xml file with the sample configuration that we are going to use in the testing and debugging.

Sample deployment unit configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:u="http://www.adroitlogic.org/ultraesb"
  xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.adroitlogic.org/ultraesb http://schemas.ultraesb.org/ultraesb-2.0.xsd">

  <u:proxy id="MyFirstProxy">
    <u:transport id="http-8280"/>
    <u:target inSequence="MyFirstSequence" inDestination="MyFirstEndpoint">
      <u:outSequence>
        <u:java><![CDATA[
          System.out.println("Reply payload : " + mediation.readPayloadAsString(msg));
        ]]></u:java>
      </u:outSequence>
      <u:outDestination>
        <u:address type="response"/>
      </u:outDestination>
    </u:target>
  </u:proxy>

  <u:endpoint id="MyFirstEndpoint">
    <u:address>http://localhost:9000/service/EchoService</u:address>
  </u:endpoint>

  <u:sequence id="MyFirstSequence">
    <u:class name="sample.SimpleJavaMediation1"/>
  </u:sequence>

</beans>

The above configuration contains a proxy service named "MyProxyService" with the in sequence of the proxy service being referred to a defined sequence with the identifier "MyFirstSequence", in destination referred to a defined endpoint with the identifier"MyFirstEndpoint", the out sequence and out destination both in-lined as a Java fragment sequence and a response type endpoint respectively.

The sequence "MyFirstSequence" has been defined as a byte code sequence, referring to the class with a fully qualified class name "sample.SimpleJavaMediation1", a sample byte code sequence shipped with UltraESB, of which the source can be found under the conf > mediation > src > java file path in the UltraESB installation home.

Adding your own sequence class
Your own byte code sequence can also be referred as in the sample class that we used for the configuration, in which case you need to add the source file of that class in addition to the binary file into the UltraRuntime project, as we are going to use the IDE to test and debug this solution.

You may follow the guide with this configuration, in which case you need to copy this configuration and replace the content of your ultra-unit.xml or use your own developed deployment unit configuration and map the relevant sections to your configuration in following the guide.

1.3.2. Running the Solution

For running the UltraESB with the above configuration or the configuration you developed in the deployment unit, there is a built in UltraESB runtime configuration. This profile loads the content from the standard conf directory so any deployment units will be loaded and installed at startup apart from the ultra-root.xml configuration.

Switch to the UltraESB runtime configuration as shown below (1) and run it (2) to run the ESB with the given configuration.

running

When you click on the Run button on the top tool bar, you will be able to see the Run panel in the bottom of the window as follows, with the console log written into the panel.

run pane

That is just what you need to do to run the solution you developed, regardless of the fact whether you have sequences/endpoints in-lined or referred and the sequences could be bytecode, Java fragments or whatever the  types, etc.. This makes it easy to run the solution while developing and it drops the development time drastically as you are just on the IDE and no need to start the ESB separately or deploy the solution to test in on a separate location.

1.3.3. Testing the Solution

Now that the solution that we have been developing is running, we can test it to see whether you see the expected behaviour from the complete application by sending a sample message through the running solution.

SOA Toolbox

For testing the solution, the SOA Toolbox can be used, which supports many convenient tools. In this particular case we have to expose a service named "EchoService" running on the port 9000 on the localhost as the back-end service, and a client to invoke the proxy service in our solution. While you can use any mock service (depending on your requirement of the actual service and its behaviour, or even you could use the actual service that you are targeting to switch to at production if it is of no harm to test over it) to replace the back-end service emulated by the toolbox, we recommend using the SOA Toolbox as the client.

SOA Toolbox supports many advance features for sending sample test messages emulating slow connections etc.. which make it really usable for testing the solution. The complete guide on the SOA Toolbox helps you understand the advance features of the Toolbox and how to use those.

Start the toolbox shipped in with the UltraESB to spin a server and a client to invoke this solution and test it.

In Unix based systems, navigate to the "bin" directory of the UltraESB installation, using a console.

$ cd /opt/ultraesb-1.6.0/bin
$ ./toolbox.sh

On Windows based systems, use the file explorer to navigate to the "bin" directory of the UltraESB installation and double click on the "toolbox.bat" file to launch the Toolbox.

Running the back-end service

SOA Toolbox ships with a service named "EchoService" configured to deploy on Jetty Server, so we are going to run that service as the back-end service for this illustration on testing the solution.

Click on the "File" menu and select New > Jetty Server from the cascading menu or alternatively the Ctrl+J shortcut key to create a new Jetty Server instance which hosts the sample services used by UltraESB.

toolbox jetty server menu

Now you should see the Jetty Server panel tab on the Toolbox application. Click on the "Start Jetty" button on the top of the pane just after the port as shown below by (1), to start the Jetty Server with the sample EchoService hosted on it;

toolbox jetty server pane scaled

You should see the Start Jetty button as a disabled button and the Stop Jetty button as an active button, once the sample Jetty server has completed starting. Once it is started, the EchoService on port 9000 having the service URL http://localhost:9000/service/EchoService should be ready.

Invoking the proxy via the client

Next we use the HTTP/S client of the Toolbox to invoke the proxy service that we have developed.

Click on the "File" menu and select New > HTTP/S Client from the cascading menu or alternatively the Ctrl+C shortcut key to create a new HTTP/S Client instance which can be used to post any HTTP/S message.

toolbox http client menu ug

Now you should see the HTTP/S Client panel tab on the Toolbox application. Using this client application we can invoke the proxy service that we have developed in our solution. To invoke the proxy service, follow the steps given below, and the respective action on the screen shot.

  1. Type the URL of the invoking service to be "http://localhost:8280/service/MyFirstProxy".

  2. Check the HTTP method on the right side of the URL to be "POST" meaning that we are going to do a HTTP POST request to the given URL.

  3. Then select the HTTP message body to be sent to the service. There are 4 pre-sets available out of which we are going to use the first one, so click on the "1" pre-set message body.

  4. Observe the message body filled in with the pre-set message 1 on the request pane

  5. Click on the "Send" button in the middle of the request and response panes to invoke the proxy service with the given message body.

  6. On the response pane you should be able to see the response, if the proxy is working from an external users point of view

client invoke

While this confirms the fact that the proxy service is working, we might want to verify the console output to see the print-lines that we have on the mediation to be invoked properly. If you look at the run panel on the bottom of the IDE you will be able to see the print-lines on the output as follows;

run pane2

Now if you need to change some logic of the referred in sequence, the SimpleJavaMediation1 class or the in-lined out sequence, you can just change it on the IDE, stop the UltraESB using the Stop button stop on left most tools of the run panel and start it back again using the Rerun button rerun again on the same tools set. This makes it really easy to do the iterative development of the solution that you are developing, without wasting time ton the building and deployment.

For example lets assume that you want to print the message number received to this proxy in this session in the in sequence, we could edit the SimpleJavaMediation1.java source file from within the IDE and re-run the UltraESB on the same IDE to see that in effect.

Press Ctrl+N short cut key to open up a class and type "Simple" and select the SimpleJavaMediation1 from the drop down, and hit Enter to open the class.

open class

You could optionally use the project browser on the left hand pane to browse to the SimpleJavaMediation1.java file.

open class browser

To open the class with project structure, open the UltraRuntime project and then open the specified folders in order, as shown in the above screen shot.

  1. Expand the project by clicking on the (+) sign before the project name.

  2. Expand the conf directory

  3. Expand the mediation directory

  4. Expand src > java > sample directories in order

  5. Double click on the SimpleJavaMediation1.java as shown above to open the Java source file.

Now to print the message count add a print-line to the execute method as follows;

public void execute(Message msg, Mediation mediation) throws Exception {
  System.out.println("SimpleJavaMediation1 = Message target : " + msg.getDestinationURL());
  count++;
  System.out.println("SimpleJavaMediation1 = Message count : " + count);
}

Now stop the UltraESB and rerun it from the run panel. Send a message again from the Toolbox client to see the output on the IDE run panel, and you will be able to see the message count printed on the output.

1.3.4. Debugging the Solution

Debugging an integration solution developed with a typical ESB is pretty hard, most of them do not support step through debugging at all, it was like JavaScript earlier days, where you used to put alerts and debug. UltraESB on the other hand provides seamless step through debugging just as how you debug today’s JavaScript code within the browser itself or your simple Hello World Java application within the IDE.

Continuing our exercise on the previous section on testing the solution that you have developed, this section walks through debugging the solution and improving it.

There are 2 types of possible debugging scenarios, which belongs to the 2 testing categorizations.

Standalone IDE debugging

Debugging the solution as an standalone application within the IDE is pretty easy and is mostly used with developer testing, where the developer finds and issue in the testing phase which is not obvious to fix, and e/she want to see what is happening internally.

To be able to step through debug while testing the solution requires the UltraESB project to be started in debug mode within the IDE.

Note
Please make sure to stop the UltraESB if it is running in the run panel, otherwise you will get a bind exception for the ports when you try to debug, as it tries to start the UltraESB transports on the same ports.

In order to start the UltraESB with the solution that you developed in debug mode, you should use the Debug icon instead of the Run icon on the top tool-bar.

debug
  1. Note that the Debug icon on the right side of the Run icon on the top tool-bar, which we use to start the UltraESB in debug mode.

  2. Note the new addition of the Debug tab into the bottom panel which is going to be automatically active, when you start the server in debug mode.

Now the UltraESB is running in the debug mode, and before sending the sample message we should put the breakpoints into the code where we want to debug. For that matter you can click on the left bar of the source editor as shown below.

This case we want to debug the execute method of the sequence class SimpleJavaMediation1.java so lets put the breakpoint at the first line of the execute method.

break point

The breakpoint is now set and we are ready to debug a single message flow.

Breakpoints for startup
If the mediation sequence initialization (init method of the sequence class) or some UltraESB starup related point debugging, you should put the break points before starting the UltraESB in debug mode

Send a message using the Toolbox client to debug the message inside the sequence. The message will be paused at our breakpoint and the breakpoint will get highlighted.

debug active

Debugging an issue within the IDE is quite easy, and the following items explains all what you have to know about the IDE features in debugging.

  1. Note the highlighted breakpoint where the message execution is paused by the debugger

  2. The Variables pane in the debug panel shows you the states and the values of all the relevant variables in the context.

  3. Watches pane allows you to watch the value of a certain variable or an expression throughout the debug session, how it changes, etc..

  4. The execution call stack or the path which the thread came to this point is shown in the Frame pane, where you can see the states of the variables on that context.

  5. The debug actions tool-bar facilitates different mandatory actions, which we will discuss shortly in more detail

  6. Debug panel tool-bar facilitates many other debug operations and controls

  7. The Console tab when switched from Debugger tab, shows the runtime output.

While you can see the complete context in the Variables pane, sometimes it is necessary to see the values/results of an evaluated expression in this context to understand/point out certain logics. In which case the Evaluate Expression tool works like a charm.

Right click on the editor and select the "Evaluate Expression" menu item from the context menu to get the Evaluate Expression tool.

eval menu

The Evaluate Expression tool will appear on selecting this menu item and type the expression that you want to see the result as follows.

evaluate

The debug actions tool-bar gives a good set of controls to support step through debugging with certain shortcut keys.

Icon Shortcut Key Action

show current execution

Alt+F10

Shows the execution points

step over

F8

Step over to the next line

step into

F7

Step into the next immediate call

force step into

Alt+Shift+F7

Force step into the next immediate call

step out

Shift+F8

Step out to the immediate caller

drop frame

Drop frame (Reverse step)

run to cursor

Alt+F9

Run to cursor

While this action tool-bar is of utmost help, the debug panel tool-bar is also facilitating many required features

Icon Shortcut Key Action

continue

F9

Resume program

stop

Ctrl+F12

Stop debugging

pause

Pause program

re debug

Ctrl+F5

Re-debug program (after stopping)

view breakpoints

Ctrl+Shift+F8

View breakpoints

mute breakpoint

Mute breakpoints

All the above controls of the IDE and the seamless integration to use these IDE debugging features help UltraESB users to develop there solutions based on the UltraESB in a flash.

Remote debugging

Remote debugging only differs from the standalone debugging, in the way UltraESB is being started and the way the IDE is being connected to the server.

Remote debugging is important and useful in environment specific issues, where the same issue might not occur in the developers development environment. These issues are mostly being discovered in the black box testing on the integration environment. In these cases the UltraESB is started as usually with parsing few special flags to the JVM, for the IDE to be able to remotely debug the UltraESB server running on the integration environment.

UltraESB supports two approaches in starting an UltraESB instance.

Standalone startup script

When running the UltraESB with standalone startup script, the ultraesb.sh or ultraesb.bat files found in the bin directory of the UltraESB installation directory.

To be able to remote debug the server started with the startup script you should pass in the "-xdebug" flag to the script as follows.

$ cd /opt/ultraesb-1.6.0/bin
$ ./ultraesb.sh -xdebug

When you start the UltraESB with passing this option, you will see on the console that the UltraESB server is waiting for a remote debug connection to start as follows.

Starting AdroitLogic UltraESB …​
Using JAVA_HOME : /opt/jdk1.6.0_23
Using ULTRA_HOME: /opt/ultraesb-1.6.0
Listening for transport dt_socket at address: 8000

Once you connect the IDE remote debugger to the host running the UltraESB server over port 8000, which is the default remote debugging port, you will be able to see the server starting up.

As a daemon with wrapper

To enable remote debugging when running as a daemon with wrapper, edit the wrapper.conf file located in the conf directory of the UltraESB installation directory and add the following additional java arguments to the next numbered additional arguments.

wrapper.java.additional.12="-Xdebug"
wrapper.java.additional.12.stripquotes=TRUE
wrapper.java.additional.13="-Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=y"
wrapper.java.additional.13.stripquotes=TRUE

Then start the UltraESB with the ultraesb-daemon.sh script found in the bin directory of the UltraESB installation.

$ cd /opt/ultraesb-1.6.0/bin
$ ./ultraesb-daemon.sh console

You will be able to see the daemon script is blocking the startup until the remote debugger is connected.

Running AdroitLogic - UltraESB…​
-→ Wrapper Started as Console
------------------------------------------------------------------------
The JVM is being launched with a debugger enabled and could possibly be
suspended. To avoid unwanted shutdowns, timeouts will be disabled,
removing the ability to detect and restart frozen JVMs.
------------------------------------------------------------------------
Launching a JVM…​
Listening for transport dt_socket at address: 8000

Once the IDE remote debugger is connected the server will resume the startup.

Connecting the IDE

In-order to connect the IDE to remote debugging, a remote debugging configuration needs to be created. For that matter click on the UltraESB runtime configuration as shown below pointed by the mouse pointer.

config

Once you click on that you will see the following drop-down menu.

edit config

Click on the "Edit Configurations" to see the configuration editing window. Click on the top left add icon to add a new configuration and select "Remote" from the drop down as shown below.

add remote

Once you click on the Remote configuration you will see the configuration properties editing pane.

remote config

Configure the newly created remote debug configuration.

  1. Give it a name, for instance we use "UltraESB-Remote" to identify the configuration

  2. Specify the host name at which the UltraESB server is running, which in our case is running on the same machine, so we use "localhost"

  3. Change the port to "8000" which is the remote debug listening port specified in the UltraESB server running remotely.

  4. Change the module or keep it as <no module> if you have more than one module in your solution project to debug

  5. Click OK to save the configuration.

Once it is saved, you will be able to see the UltraESB-Remote runtime configuration is selected and the Debug icon (re debug) enabled, while Run icon is disabled (as this configuration is only for remote debugging)

Click on the Debug button as shown in the following screen shot to attach to the remote UltraESB server.

Enable port 8000
If you are running the UltraESB server on a hardened system behind a firewall, you might want to unblock the port 8000 such that the IDE debugger can attach to the UltraESB.

Put a breakpoint as in the standalone case and send a message to the remote UltraESB server, where you will be able to debug that message flow from within your IDE with all the debug options in standalone mode applied exactly the same to the remote debugging session too.

Advance remote debug options

You can change the port from 8000 to any port available to use, by editing the ultraesb.sh/bat and replacing the 8000 in the following string. Same way you could change the port that you specify for the wrapper.conf

XDEBUG="-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,address=8000"

You could change the behaviour of the debugger to not to suspend the startup by changing the above line to read as follows. Note the addition of suspend attribute. Same way with wrapper you can change the suspend value to "n" to not to suspend the server startup

XDEBUG="-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n"

1.4. Solution Deployment

This section describes the deployment of the solution that you have developed and tested in an integration or a production environment. While this concentrates on the solution deployment onto an already installed UltraESB instance in this chapter, please refer to the Deployment Guide on how to do a production deployment of the UltraESB server.

Once the testing and iterative development of the solution is complete, most of the time that solution will be deployed into an integration server. An integration server is nearly equivalent to the production setup that the solution is planed to be launched.

Since we have done the development on the IDE itself within an UltraESB project first thing is to identify the deployable artifacts that we need to move.

  1. First and the most relevant artifact is the deployment unit, which contains one or more configurations files including "ultra-unit.xml" and optionally third party or custom libraries and compiled classes

  2. If you have any custom beans placed at "ultra-custom.xml", you should include that.

  3. The root configuration file "ultra-root.xml" needs to be migrated with care

  4. Any files like script files, Java source files

If you look at these files carefully, apart from the jar files containing any byte code (class file) sequence and third party libraries if there are any, rest of the files are all in the conf directory or a sub directory of the conf directory of the UltraESB installation directory.

The migration from the development setup to the integration or into production can be done with keeping history by using a version control system. All configuration files being XML and source files (which are text files) best option is to use SubVersion, JIT, or Mercurial repository to commit all the configuration files.

Source control based configuration management
Source (version) control systems provide many advance features to manage the configuration management of UltraESB as most of the configuration files are text files. The configuration updates and continues development using the version control system makes it a smooth process to mange multiple versions of configurations without mixing the thing in development, integration and production.

Then from the integration deployment, you just need to take a checkout of the repository, which will automatically update the relevant configuration files.

Once the integration setup is done based on a version control system, the process of updating the configurations etc.. is going to be very convenient and natural, as the development environment can use a trunk to develop and the production deployments can use a stable tag to deploy on production and managing production updates.

More information on production deployment and configuration management can be found under the Deployment Guide.

Back to Home Page