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.

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[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-4.2.xsd
http://www.adroitlogic.org/ultraesb http://schemas.adroitlogic.org/ultraesb/v2_6/ultraesb-artifacts.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.

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.

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 7. 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 7. A 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

print("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>
In this topic
In this topic
Contact Us