JBoss.orgCommunity Documentation

Chapter 3. Conversation Aware ESB

3.1. Conversation based Conformance
3.1.1. Overview
3.1.2. CDL Conformance Checking
3.2. Stateful "Conversation Aware" ESB Actions
3.2.1. Overview
3.2.2. Conversational Service
3.2.3. Establishing Correspondance between ESB Configuration and Choreography
3.2.4. Managing Sessions
3.2.5. Interacting
3.2.6. Managing Information
3.2.7. Controlling Flow
3.3. Stateless "Conversation Aware" ESB Actions
3.3.1. Overview
3.3.2. Interaction
3.3.3. Controlling Flow
3.4. Generating a JBossESB Configuration from CDL
3.4.1. Overview
3.4.2. Generating the JBossESB Configuration
3.5. Dealing with Conformance Issues
3.5.1. Overview
3.5.2. Show referenced description
3.5.3. Error: Expecting additional activities as defined in referenced description
3.5.4. Error: Type mismatch with referenced description, was expecting '...'
3.5.5. Error: Behaviour not present in referenced description
3.5.6. Error: Additional unmatched paths in model
3.5.7. Error: Additional unmatched paths in referenced description

In general, conformance checking is the procedure for ensuring that a component has been correctly built according to some specification or standard. In terms of CDL, it more specifically ensures that one or more services perform their responsibilities correctly in accordance with the choreography description.

The pi4soa tools suite provide the mechanism for producing service endpoint descriptions for each service within a choreography description. The relevant service descriptions can then be compared (for conformance) against their ESB service implementations.

However, to make this possible, it is necessary to be able to derive the communication 'type' structure from the ESB implementation, i.e. where messages (of particular types) are sent and received, where decision points are, where actions are performed concurrently, etc.

This is why a specific set of 'conversation aware' ESB actions have been defined (discussed in a later section), to make it possible to derive the communication 'type' structure from an ESB service implementation.

Once the communication 'type' structure has been obtained from the ESB implementation, it can be compared against the relevant service endpoint description projected from the choreography description, to determine if there are any differences. These can then be reported to the ESB service developer, so that they can fix the problems, before the service is deployed to the runtime environment.

This ensures that all of the services will interaction correctly, as they will all have been validated against the choreography, and therefore work together by design.

In the following two sections, we will describe how ESB services can be described using either Stateful or Stateless "conversation aware" ESB actions. The benefits of each approach will be discussed.

The top level component is the Service, which will have a single endpoint reference (i.e. service category and name) that will be used by external clients (or other services) that interact with this service.

However the service behaviour is stateful, and therefore will need a means of routing the inbound request to the appropriate service descriptor that is (a) capable of handling the request, and (b) the service instance is in an appropriate state where the service descriptor can be executed.

The action used to perform routing of the inbound requests is called MessageRouterAction, for example:




    <service category="ESBBroker.BrokerParticipant" name="ESBBrokerProcess" description="">
        <listeners>
            <jms-listener name="BrokerServiceListener"
                          busidref="BrokerService"
                          maxThreads="1"/>  
        </listeners>
        <actions mep="OneWay">              
            <action class="org.jboss.soa.overlord.jbossesb.stateful.actions.MessageRouterAction"
                        process="process" name="s0-1">
                <property name="paths">
                    <route  service-category="ESBBroker.BrokerParticipant"
                            service-name="ESBBrokerProcess.main" 
                            initiate="true">
                        <message type="enquiry">
                            <identity type="primary" >
                              <token name="id" locator="//@id" />
                           </identity>
                        </message>
                    </route>
                    <route  service-category="ESBBroker.BrokerParticipant"
                            service-name="ESBBrokerProcess.main.5" >
                        <message type="buy">
                           <identity type="primary" >
                             <token name="id" locator="//@id" />
                           </identity>
                        </message>
                        <message type="cancel">
                           <identity type="primary" >
                             <token name="id" locator="//@id" />
                            </identity>
                        </message>
                    </route>
                </property>             
            </action>
        </actions>
    </service>
                 

In this example, the 'service' endpoint reference will be associated with the service category "ESBBroker.BrokerParticipant" and name "ESBBrokerProcess". All inbound requests to an instance of this service will be routed via this service descriptor.

This service descriptor therefore only has a single action, which represents the message routing capability. The action class is org.jboss.soa.overlord.jbossesb.stateful.actions.MessageRouterAction. This action only defines a single property 'path' which defines one or more 'route' elements. The attributes associated with this 'route' element are:

The 'route' element will contain one or more 'identity' elements, and one or more 'messageType' elements.

The 'identity' element is used to extract information from the inbound message that can be used to identify the appropriate service instance. The only attribute on the 'identity' element is the type of identity, which can be:

The one or more 'token' definitions contained within the 'identity' element provide the details regarding the structure of the identity. The token has 'name' and 'locator' attributes, the locator being used to provide an expression that locates the identity information within the inbound message. If more than one token is defined, it provides a composite identity (i.e. made up of multiple parts).

The one or more 'messageType' elements, contained within the 'route' element, defines the message type(s) that should be routed to the service descriptor associated with the 'route' element.

If no routes are found for a particular inbound message, then an exception will be reported.

All actions (and therefore service descriptors) for a particular service implementation must be defined within the same ESB configuration file. This is a current requirement, to ensure that all of the inter-related service descriptors are available to support the static validation (e.g. conformance checking).

The jboss-esb.xml file must be defined within either the same Eclipse project as the pi4soa choreography description (.cdm file), or in a project that has a 'project reference' to the project containing the choreography description.

To establish the link between the choreography description and the jboss-esb.xml, both must 'implement' a common conversation type.

The conversation type is specified in the CreateSessionAction ESB action, described later in this section, and is associated as a semantic annotation against the relevant Participant Type or Participant Instance within the choreography description.

To associate the conversation type with either the Participant Type or Instance, open the choreography description in the pi4soa choreography designer. Then select the "Choreography->Edit Annotations" menu item from the popup menu associated with the Participant Type or Instance. In the lefthand panel, select "Add Freeform Annotation" from the popup menu, then specify "conversationType" as the annotation type and press 'Ok'. Then select the 'Annotation' tab in the righthand panel, and enter the conversation type, e.g. "overlord.cdl.samples.LoanBroker@Broker". Note the '@' is important, as the following word indicates the 'role' associated with the conversation type which precedes the '@' symbol.

A "session" represents a specific instantiation of a service definition that is involved in a business transaction (or conversation). The "session" will be distinguished based on unique identity information relevant to the business transaction, that is derived from specific properties within the messages being exchanged by the interacting services.

The service description can be composed from other reusable sub-service descriptions, although the service can only define a single 'root' (i.e. top level) definition.

Each top level or sub-service description will be associated with a business state 'pojo' class that contains its business relevant information and logic (i.e. methods). This class is identified by the property 'session', which will be associated with the initial conversation based ESB actions in a service (or sub-service) description, or in any subsequent conversation based ESB actions that require the information to determine the session instance.

As well as representing the business state and logic for a session (or sub-session), the pojo can define an annotation that provides information about the session. The annotation type is org.jboss.soa.overlord.jbossesb.stateful.actions.Service.

The 'name' attribute represents a name associated with the complete service description, encompassing both top level and composed sub-session behaviour. The 'root' attribute indicates whether this pojo is related to the top level session, or a sub-session.

For pojos that represent the 'root', or top level session, for a service description, they should also specify the optional 'conversationType' attribute. This expresses the type that will be checked for conformance, and is comprised of two parts separated by the '@' symbol. The first part is a fully qualified name of the conversation type. The second part represents the role being played within the conversation type.

If the Service annotation is not defined on the pojo, then the information (service description name, root and optional conversation type) must be explicitly defined in the relevant conversation based ESB actions.

Certain service descriptors, and actions within those service descriptors, will need to be able to access the session in which they are executing. In many situations the session will automatically be available due to prior activities that may have occurred, causing the session reference to be cached and retrieved when required.

However, in some situations (such as receiving a response message from another service) there may not be enough context information to understand which session should be retrieved from the database to handle the incoming message.

The solution to this problem is to ensure that the first "conversation aware" ESB action in the receiving service descriptor has the additional information required to resolve the context. This information will include:

Services interact by sending and receiving messages, whether synchronously or asynchronously.

JBossESB is designed to anonymously handle inbound messages (possibly requests), without explicitly defining restrictions on message type, and then optionally returning responses (again without explicitly defining the response message type).

Although this is sufficient for a runtime mechanism, where issues related to unexpected message types can be handled with suitable exceptions/faults, it does not enable the communication type structure to be understood by examination of the JBossESB configuration.

Therefore, the set of "conversation aware" ESB actions include actions for sending and receiving messages. Although these actions are not strictly necessary for the ESB to process messages, they make the communication behaviour of the ESB service explicit, which enables it to be statically checked (validated) against a description of the expected behaviour.

When sending a message, the first thing to consider is the type of the message. This can be declared as a property on the SendMessageAction. If dealing with RPC style interactions, then we may also want to optionally specify an operation name.

In this example, the message type has no 'namespace'. If a namespace is appropriate, it can be defined inside {} curly braces (e.g. "{http://www.jboss.org/examples}requestForQuote" for an XML type, or "{java:org.jboss.example}Quote" for a Java type).

The next important aspect is to define the destination of the message. This will be dependent upon whether the message being sent is a request or a response/notification.

The final part of the SendMessageAction is the identity declaration. See discussion on Message Identities early in this chapter.

The identity information extracts values from the message content being sent, and determines whether it correlates with the identity already associated with the session (or sub-session). If the message is correctly correlated to the session, then it will be sent. Otherwise an exception will be generated.

It is possible that multiple identities can be defined, associating new 'alternate' or 'derived' identities with the session (or sub-session). These can be used to link subsequent messages (send or received) to the same session.

The ReceiveMessageAction is used to explicitly define the message type that should be received. If an RPC style has been used, then the optional operation name can also be defined.

Unlike the SendMessageAction, which will actually send a message to the specified service category/name, the ReceiveMessageAction primarily serves to provide explicit details about the expected message and to perform any relevant validation of the message content, including conforming that the extracted identity details correlate correctly with the session (or sub-session). If an incorrect message type is received, or an appropriate session cannot be located, then an error will be logged.

The optional 'clientEPR' property is used to store any specific "reply to" EPR (associated with the message) against the specified name. This makes the EPR accessible to any subsequent SendMessageAction activities that need to return a response or send a notification.

As previously mentioned, each session or sub-session is associated with a business state pojo which contains the information required by the session. The relevant class is identified by the 'session' property on appropriate "conversation aware" ESB actions.

When an action needs to access (read) information defined on this business state pojo, it will simply define an expression that can access (and navigate) the properties and invoke methods on the object where appropriate.

However we also need to have the ability to modify the state information. This is achieved using the SetStateAction. For example,

With this action, it is possible to specify a target 'variable' on the pojo business object, associated with the session (or sub-session), and have the value associated with an expression assigned to that variable.

In the example above, the expression is defined using the 'stateExpression' property. This expression will be applied to the pojo business object associated with the session (or sub-session), to extract information from variables, or invoke methods on the object.

The other type of expression that can be used is defined in the 'messageExpression' property. This will apply the expression to the content of the current message on the ESB action pipeline.

This section describes the various control flow mechanisms that are supported by the "conversation aware" ESB actions.

The default control flow, supported natively by the ESB action pipeline design, is a sequence. As the name implies, the actions are performed one at a time in the order they defined in the action pipeline, i.e. in a sequence.

The action associated with the 'selection of a path based on a decision' is the IfAction. An example of this construct is:

This construct defines a 'path' property with one or more elements, representing the if, elseif and else aspects of the traditional if/else construct. Only the if element is mandatory, and can be followed by zero or more elseif elements before ending with the optional else element.

The if and elseif elements can define an 'expression' attribute to be evaluated at runtime, to determine if the associated 'service-category' and 'service-name' should be invoked.

If the 'immediate' boolean attribute is defined as true on any of the elements, it means that the associated service category/name should be invoked immediately (i.e. it represents a control link). However, if this attribute is false, or not specified, then the associated service category/name is expected to be triggered upon the receipt of a message from an external source.

The action used to select paths based on a received message type is SwitchAction. For example,

The 'paths' property defines one or more 'case' elements. These elements identify a service category and name that should be invoked upon receipt of one or more message types, as specified by 'message' elements contained within the 'case' elements.

The 'type' attribute on the 'message' element defines the type of message that can be routed to the specified service category/name. In the example above, the message types have no namespace. However if they have a namespace, this can be defined in curly braces, e.g. "{http://www.jboss.org/samples}buy".

Once a path has been selected, the associated service category/name will be invoked immediately. If none of the paths specified within this action are relevant to the received message, then a runtime exception will be thrown.

The ParallelAction is used to initiate multiple concurrent threads of activity. These are represented by the 'path' elements within the 'paths' property. Each path identifies its service category/name and also whether it should be invoked immediately (i.e. 'immediate' attribute set to 'true'), or will be triggered by a message from an external source.

The other element contained within the 'paths' property is the 'join' element, which represents the service category/name that acts as a convergence point across all of the concurrent threads. When all of the initiated threads have completed, the service category/name associated with the 'join' element will be invoked.

The mechanism for performing repetition is through the use of two actions, WhileAction and ScheduleStateAction. The WhileAction defines the condition to be evaluated, and the two relevant paths, i.e. one that enters the loop body and one that represents the activities that occur after the while loop, when the conditions have not been met. The ScheduleStateAction is used within the loop body to return back to the service descriptor containing the WhileAction, to cause the loop to be re-evaluated.

For example,

The WhileAction defines a 'paths' property which contains two elements, a 'while' and an 'exit' element. Both elements define the service category and name they will invoke, and whether the service descriptors will be triggered immediately or based on an incoming message from an external source.

Additionally, the 'while' path defines the condition that will decide whether to enter or skip the loop.

Then at some point in the activities directly or indirectly associated with the service descriptor "ESBBroker.BrokerParticipant/ESBBrokerProcess.main.2", there would be,

while results in the service descriptor associated with the WhileAction being re-evaluated (i.e. executed again). The ScheduleStateAction will define the service category and name to invoke, and whether to invoke them immediately, or whether the service descriptor will be triggered via an incoming message from an external source.

The ability to compose reusable modules into higher level functions is a useful capability in any language. This mechanism is also supported in the "conversation aware" ESB actions, using the PerformAction to invoke a sub-session. For example,

The 'serviceCategory' and 'serviceName' properties define the service descriptor that will be invoked (i.e. that represents the sub-session). This service descriptor must begin with a CreateSessionAction, to indicate that it represents the start of a sub-session.

The optional 'returnServiceCategory' and 'returnServiceName' represent the service descriptor that will be invoked once the sub-session has completed, to enable the parent session to continue. If these properties are not defined, then it means that sub-session is being performed asynchronously, and therefore the parent session will not wait for it to complete.

The optional 'bindDetails' provides the means for the parent session to assign specific information from its state to the newly created pojo associated with the child session.

The optional 'parentReference' is used to set a reference, on the child session's pojo, to the parent session's pojo. The value of the 'parentReference' identifies the property on the child session's pojo that will be used to reference the parent pojo.

Firstly, let's see the two basic actions for interaction. Services interact by sending and receiving messages, whether synchronously or asynchronously.

JBossESB is designed to anonymously handle inbound messages (possibly requests), without explicitly defining restrictions on message type, and then optionally returning responses (again without explicitly defining the response message type).

Although this is sufficient for a runtime mechanism, where issues related to unexpected message types can be handled with suitable exceptions/faults, it does not enable the communication type structure to be understood by examination of the JBossESB configuration.

When sending a message, the first thing to consider is the type of the message. This can be declared as a property on the SendMessageAction. If dealing with RPC style interactions, then we may also want to optionally specify an operation name.

This section describes the two control flow mechanisms that are supported by the stateless ESB actions.

The default control flow, supported natively by the ESB action pipeline design, is a sequence. As the name implies, the actions are performed one at a time in the order they defined in the action pipeline, i.e. in a sequence.

The action associated with the 'selection of a path based on a decision' is the IfAction. An example of this construct is:

This construct defines a 'path' property with one or more elements, representing the if, elseif and else aspects of the traditional if/else construct. Only the if element is mandatory, and can be followed by zero or more elseif elements before ending with the optional else element.

The if and elseif elements can define an 'decision-class' attribute to be evaluated at runtime, to determine if the associated 'service-category' and 'service-name' should be invoked. the value of decision-class must implement the interface of org.jboss.soa.overlord.jbossesb.Decision.

The action used to select paths based on a received message type is SwitchAction. In the stateless esb actions approach, we are using this as the Message Router. The configuration of SwithAction is like:

In this approach, the SwitchAction typically is the point of contact for other services. Also true for the internal services. In the same manner as the Stateful ESB actions, it is necessary to specify the 'conversation type' that the service represents, to enable conformance checking to be performed against a choreography description that provides the associated conversation type. In the Stateless ESB actions, this initial SwitchAction defines this information in the conversationType property.

The 'paths' property defines one or more 'case' elements. These elements identify a service category and name that should be invoked upon receipt of one or more message types, as specified by 'message' elements contained within the 'case' elements.

The 'type' attribute on the 'message' element defines the type of message that can be routed to the specified service category/name. In the example above, the message types have no namespace. However if they have a namespace, this can be defined in curly braces, e.g. "{http://www.jboss.org/samples}buy".

The 'event' element is defined for paths with no associated message type. These paths are expected to be triggered by a different sort of event, for example an internal timeout managed by the service implementation. However these internal events are triggered, and directed to the appropriate service descriptor is a implementation issue for the service. The inclusion of this path in the SwitchAction symbolises the exist of this asynchronously triggered path in the behaviour of the service.

Once a path has been selected, the associated service category/name will be invoked immediately. If none of the paths specified within this action are relevant to the received message, then a runtime exception will be thrown.

When the choreography description has been completed, and has no errors, the user should select the "Overlord->Generate->JBossESB Services" menu item from the popup menu associated with the choreography description (.cdm) file.

When the dialog window is displayed, it will contain the list of services that can be generated, along with the project names that will be created. The user can unselect the services they do not wish to generate (also using the 'Check All' or 'Clear All' buttons). There is also a checkbox to determine whether a stateful or stateless (the default) implementation should be generated.

The user can also select their preferred build system, which will create the relevant build structure and script in the generated Java project to enable the JBossESB service to be deployed, as well as the appropiate messaging system to use.

If there is a problem with the name of the project select, such as invalid characters used in the name, or the project name already exists, then it will be displayed in red.

In the above image, on the left it shows the generated project structure for the Broker service role. On the right it shows a portion of a generated session class, with the accessor and modifier for one of the variables associated with that session.

Although an initial build script will be created, depending on the build system selected, the user may need to edit the script to set certain properties, or change the way the build occurs. For example, with the Ant build, the deploy target (which is the default) will attempt to place the deployed .esb file into a location defined by the ${org.jboss.esb.server.deploy.dir}. If this variable has not been defined, then a folder called ${org.jboss.esb.server.deploy.dir} will be created in the root folder of the project, containing the .esb file.