Scribble.orgCommunity Documentation

Chapter 3. Java Runtime

3.1. Overview of the Java Runtime
3.1.1. Service Description
3.1.2. Common Components
3.1.3. Session
3.1.4. Service Repository
3.1.5. Service Tracker
3.1.6. Session Manager
3.1.7. Identity Manager
3.1.8. Service Container
3.1.9. Message Handler
3.1.10. Service Registry
3.1.11. Timeout Manager
3.1.12. Extension Resolver
3.1.13. Service Monitor
3.2. Choreography Description Projection
3.2.1. Identifying the Participants and Roles
3.2.2. Projecting a Participant or Role
3.2.3. Projecting Choreography Description Components
3.3. Service Description Generation
3.4. Service Interface Generation
3.4.1. Interface Generation
3.4.2. Interface Introspection
3.5. Service Endpoint Monitoring
3.5.1. Obtaining a Service Endpoint Monitor
3.5.2. Registering Service Descriptions
3.5.3. Reporting Message Exchanges to the Monitor
3.5.4. Detecting Unexpected and Out of Sequence Messages
3.6. Service Endpoint Execution
3.6.1. Obtaining a Service Container
3.6.2. Message Handlers
3.6.3. Client Side Service Instantiation

This section describes the steps required to obtain an endpoint projection associated with a Choreography Description.

As mentioned in the previous section, the projection mechanism makes use of the visitor pattern, to modify the visited information in such a way to present it relative to the participant type or role type of interest. However, the actual components projected are the same types.

Therefore, in some situations, it is necessary to modify the information that is visited to provide the destination visitor with a clue as to how they should interpret the visited information. This section lists the details of how these clues should be interpreted, when building your own target projection visitors.

  1. org.pi4soa.cdl.Interaction

    When a projected visitor is passed an Interaction component, this will usually reflect information relevant to both parties involved in the interaction. However, from a projection perspective, we are only interested in the information relevant to the role/participant being projected.

    Therefore, the projecting proxy hides the information associated with the other party, only making available information required by the projected party. This includes,

    • the timeout record details only for the relevant role type (from or to), the other roles timeout record details will return an empty list
    • only the record details that are relevant to the projected role/participant
  2. org.pi4soa.cdl.ExchangeDetails

    As with the interaction type, the exchange details provide information concerning both parties in the interaction. Therefore the projecting visitor proxy hides information not relevant to the projected role or participant type. This includes,

    • the send and receive variable information – only one of the variables will be relevant, depending on whether the projected role is the sending or receiving party. The other variable will return null. As the variable field is optional, and therefore may be null in the real choreography description, this is catered for by returning an empty variable for the projected role/participant. This can be determined by the fact that the variable's name is null.
    • the send/receive variable part information – only the projected role/participant will return information, otherwise null – however this field is also optional, so both the sending and receiving variable part information may be null.
    • the record details for the sending or receiving role will be returned, depending on the role assumed by the projected role/participant type – the other record details list will be empty
    • cause exception fields – only the projected role will return the real value, which may be null anyway as the field is optional

The org.pi4soa.service.behavior.projection.BehaviorProjection class provides a static convenience method for performing the projection of a Choreography Description based on a Participant Type, called projectServiceDescription. There are two variations of this method, one that takes the CDL file path and participant type name, and the other that takes the loaded CDL package, participant type object and an optional artifact manager. The artifact manager is provided to enable associated artifacts to be located (e.g. WSDL files).

For example,

Where the artifacts exist within the file system, as structured in the Eclipse pi4soa designer (i.e. in sub-folders beneath the folder containing the Choreography Description file), then the org.pi4soa.common.resource.FileSystemArtifactManager implementation can be used. This class takes the root folder as an argument to its constructor.

This implementation of the artifact manager expects to find sub-folders in the specified root folder named after the CDL package and artifact type. For example, if a Choreography Description has a CDL Package component with name 'simplerfq', and the artifact type is 'wsdl', then it will expect to locate the artifacts in a sub-folder called "simplerfq_wsdl".

A simple version of the projection method also exists, which takes the CDL file path and the name of the participant. For example,

In addition to being able to generate the skeleton behavior for a service endpoint, in a variety of executable languages, the choreography description can also be used to generate interface descriptions for the services involved in a choreography.

Once an interface exists for a service involved in a choreography, whether generated from the choreography or pre-existing, it is possible to use the definition of the service interface to constrain subsequent interactions with that service to only the operations defined on the interface – this is called interface introspection.

This section describes how to generate an interface description from a choreography description, and then how to write an interface introspector for use in validating a choreography description against an existing service interface description.

The first step in generating interfaces for a choreography description is to obtain a reference to the Interface Deriver. This component is responsible for returning a description of the interfaces from a choreography description and can be interrogated using two approaches.

The Interface Deriver implements the interface org.pi4soa.cdl.interfaces.InterfaceDeriver, and can be obtained from a static factory class, e.g.

The first approach for accessing interface information is to use a visitor pattern. The visitor interface to be implemented is org.pi4soa.cdl.interfaces.InterfaceVisitor. This visitor has methods related to the role types, interfaces, operations and message definitions. The visitor is initiated using a method on the deriver, e.g.

The other approach is to directly traverse an object model representing role types, interfaces, operations and messages derived from the choreography description.

This can be used to obtain all of the role type definitions for a choreography description. Alternatively, if a particular role type definition is required, then the 'getRoleTypeDefinition()' method can be used which takes the choreography description and role type.

Once a role type definition has been obtained, it can be used to traverse the associated interface definitions. See the javadocs for more information on these classes.

Generating an interface description can be invoked under user control from an action presented in the Eclipse user interface. The pi4soa tools do not currently provide any other general infrastructure support for plugging in these generation capabilities. They are implemented as part of separate plugins that are responsible for registering their own Eclipse menu actions, creating the relevant artifacts, handling any merging issues, and also performing any necessary validation prior to allowing the generation to occur.

One general principle that should be followed is that no generation should occur if there are errors outstanding on the associated choreography description.

Interface introspection is the mechanism for analysing an interface description, in a known format, to build a representation of that interface in a generic representation that can be used by other pi4soa tools. This enables the other pi4soa tools to remain independent of the interface format.

An interface introspector implements the interface org.pi4soa.cdl.interfaces.InterfaceIntrospector.

This interface has the following methods:

To register an introspector implementation, to enable other tools to make use of it, the InterfaceFactory provides a static method, e.g.


The org.pi4soa.cdl.interfaces.InterfaceFactory also provides static methods for unregistering an introspector, returning the list of registered introspectors, and obtaining an introspector for a particular module id.

Any registered introspectors will be used as part of the standard choreography description validation, if appropriate interface definition files have been placed in the appropriate sub-folder for the choreography description and interface format. These validation rules will interate through the available introspectors until an interface definition is found for a particular namespace and local name.

This section discusses the use of the components associated with the Service Endpoint Monitor.

A Service Endpoint Monitor is the mechanism used to enable a transport mechanism to be observed to ensure that the message flow conforms to a Service Endpoint description configured within the monitor.

The monitor provides a defined interface to enable messages that are being sent or received to be recorded. How the monitor is integrated with the message flow (transport mechanism) is out of the scope of this document. This will vary depending upon the technology being used.

Before describing how service monitors are created, we will first discuss the information required when instantiating a service monitor, namely the monitor configuration.

When retrieving a service monitor, the application needs to provide some configuration information. This monior configuration is provided by an implementation of the org.pi4soa.service.monitor.MonitorConfiguration interface.

There is a default implementation of this interface in the same package, called DefaultMonitorConfiguration, which contains default values for each of its properties. There is also a XMLMonitorConfiguration class that initializes itself with appropriate implementations of the relevant components (listed below) based on properties defined in a file within the classpath called pi4soa.xml.

This configuration information is used to identify the following information:

The default implementation of the ServiceRepository is initially empty, until the embedding application obtains a reference to it (either from the configuration or from the service monitor), and adds the required service descriptions.

To enable message exchanges to be reported to the Service Monitor, the monitor's interface provides the means to create a message that encapsulates the relevant details. Once created, this message can then be dispatched to the monitor for comparison against the registered service descriptions and active sessions.

There are two methods for creating the message, one for requests and one for responses. Both methods take the same set of arguments, but represent different directions in the conversation between two participants.

The arguments to the 'createRequest' and 'createResponse' methods are:

String opName The operation name. String faultName The optional fault name – in general this will only relate to the response, but WSDL2.0 supports faults in the request message aswell. String serviceType The service type represents the fully qualified type of the endpoint that represents the service within the conversation. EndpointReference serviceEndpoint The endpoint reference represents a specific location for the service instance. This information is not always available, especially within the service implementation, and is therefore optional from the monitoring perspective. However it can be useful from an audit trail perspective. java.io.Serializable value The value associated with the message. Identity sessionId The optional session id This field is only specified if explicit identifies are being used. Otherwise the identity details will be derived from the business Identity channelIdentity The optional channel id. This field is only specified if explicit identifies are being used. Otherwise the identity details will be derived from the business message.

To dispatch the message to the monitor, there are two methods that indicate whether the message was being sent or received. For example, when a message is being sent:

org.pi4soa.service.Message mesg=monitor.createRequest("helloWorld", null, "{http://www.pi4soa.org/}HelloWorldService", endpointRef, value, null, null); monitor.messageSent(mesg);

or when a message is being received:

org.pi4soa.service.Message mesg=monitor.createResponse("helloWorld", null, "{http://www.pi4soa.org/}HelloWorldService", endpointRef, value, null, null); monitor.messageReceived(mesg);

Note

The format of the service type is a QName, which is represented as a namespace enclosed in braces followed by the local part, e.g. {namespace}localpart.

This section discusses the use of the components associated with the Service Endpoint execution.

A Service Container is the environment in which service endpoint instances are executed. An embedding application only needs to access a service container for three reasons,

Service endpoints may be used within a simple application, to enable the execution of a single endpoint instance on behalf of that application, or in a server environment, where the container is managing many service endpoint instances (for one or more service descriptions).

Before describing how service containers are created, we will first discuss the information required when instantiating a service container, namely the container configuration.

When retrieving a service container, the application needs to provide some configuration information. This container configuration is provided by an implementation of the org.pi4soa.service.container.ContainerConfiguration interface.

There is a default implementation of this interface in the same package, called DefaultContainerConfiguration , which contains default values for each of its properties. There is also a XMLContainerConfiguration class that initializes itself with appropriate implementations of the relevant components (listed below) based on properties defined in a file within the classpath (pi4soa.xml) if present. (NOTE: A property file is provided with the org.pi4soa.common plugin, which is used to configure actions performed within the Eclipse environment). See the section on XML Configuration for details of the structure of this property file.

This configuration information is used to identify the following information:

An example of creating the configuration information is:


Generally the org.pi4soa.service.repository.ServiceRepository and org.pi4soa.service.registry.ServiceRegistry can remain the default values, unless an alternative implementation is required.

The default implementation org.pi4soa.service.registry.DefaultMutableServiceRegistry of the Service Registry can read discovery details from a file within the classpath called "pi4soa_service_registry.properties". The contents of this file is a set of properties of the form "serviceType = URL". This default service registry also has a constructor that enables the application to specify the path of the property file that it wishes to use to initialize the registry.

The default implementation of the Service Repository is initially empty, until the embedding application obtains a reference to it (either from the configuration or from the service container), and adds the required service descriptions. There is an alternative implementation, org.pi4soa.service.repository.FileBaseServiceRepository, that is initialized from the file called 'pi4soa_service_repository.csv', which stores information in a two column comma separated format. The first column defines the path to the .cdl file, and the second column defines the participant of interest within that CDL model.

The Message Handler is an interface used to enable the service endpoint to send requests to other service endpoints, and send responses or faults to service clients. It provides the means to integrate transport technologies into the service execution environment, although it can also be used by the application to handle message routing itself (internally) between different service containers.

The message handler interface is comprised of the following methods:

This section will describe how the message handlers are configured and used within the service container.

When a service endpoint makes a request/response invocation to another service endpoint, it will be necessary to perform the invocation in an asynchronous manner. This is because the service endpoint execution operates in an asynchronous manner, and may potentially perform other activities in between sending a request and receiving a response (or fault). The state machine must therefore not block pending the receipt of the response.

To help develop message handlers that can perform synchronous request/response invocations in an asynchronous manner, there is a support class called org.pi4soa.service.container.MessageHandlerInvocation.

This class can be used to perform the service invocation in a separate thread, and then dispatch any response or fault message, into the service container, as appropriate.

An example of using this support class is in the Axis client message handler, which is derived from the org.pi4soa.service.container.AbstractMessageHandler to manage the message dispatcher (associated with the handler) and schedule the asynchronous invocation for execution. The relevant code fragment is shown below:


When implementing a Message Handler, it is sometimes useful to be able to store information with the message flow, that can be used to correlate back to the technology specific transport session that the message handler represents. For example, if a message handler can represent more than one transport session, then we need to be able to associate the specific session on which a request was received, so that the response can be sent back on the same transport session.

One way to achieve this is to implement the following steps in the message handler:

  1. Prior to dispatching the message, store the relevant information in the message properties
    if (getMessageDispatcher() != null) { Message mesg=getMessageDispatcher().createRequest(opName, null, serviceType, null, value); String sessionKey=getSessionKey(session); mesg.setProperty(AXIS_SESSION, sessionKey); ret = getMessageDispatcher().dispatch(mesg); }

    This example is taken from the Axis Server message handler, which is derived from the org.pi4soa.service.container.AbstractMessageHandler (which provides access to the Message Dispatcher). The properties associated with the message must be serializable. As the Axis session is not serializable, it is necessary to obtain an indirect reference to that session, which is serializable, which can then be resolved back to the session at a later time.

  2. In the acknowledgement of the request, transfer the stored details from the message into the supplied channel
    public void acknowledge(Message message, Channel channel) throws ServiceException { channel.setProperty(AXIS_SESSION, message.getProperty(AXIS_SESSION)); }
  3. When the response or fault is processed by the handler, extract the information from the channel, and use to send the message
    String sessionKey=(String)channel.getProperty(AXIS_SESSION); org.apache.axis.session.Session session=resolveSession(sessionKey);

    This fragment is from the 'process' method on the Axis server message handler. Once the session has been resolved, the message can be sent back to the client via the returned Axis session.

When a Service Container is being used to represent a role or participant that is playing the service side of a collaboration, then it will automatically create new Service Endpoints when necessary, based on the inbound requests.

However, when a Service Container is being used to execute Service Endpoints that are performing the client side of a collaboration, then we need a mechanism for triggering the instantiation of a new Service Endpoint instance.

The Service Container interface provides a method for achieving this, called 'newServiceInstance'. This causes the new service endpoint, for the supplied service description, to be created and initiated. It is then the responsibility of the service endpoint execution to perform the necessary steps to either interact with other service endpoints, or perform an activity that will result in custom extension code being performed, which then integrates back into the application to determine what should occur next.

An example of performing this method is:


The newServiceInstance method takes the Service Description for the endpoint that needs to be instantiated, and an set of variables. The supplied variables will be used to initialize the top level choreography, which can then also be used by extensions to determine the session they are processing.

There is also another variation of the newServiceInstance method on the service container, which additional takes an optional session identity (org.pi4soa.service.Identity).

The session identity should only be explicitly supplied where the environment embedding the Service Container will consistently supply this session identity with each inbound message. Otherwise, the identity attributed to a session instance will be obtained from the contents of the messages exchanged between participants. Whichever identity approach is used, must be maintained for the life of the choreography session instance.

Another consideration, when determining whether to explicitly provide the session identity, is if a central monitoring utility will be used. In this case, each participant that is reporting monitoring information related to the session would need to use the same (set of) identity value(s).

If a client side application is only interested in initiating a single session, and then being informed when that session has completed, then the application must register a listener against the session manager used by the Service Container.

The session manager is responsible for managing the lifecycle of each session executed within the Service Container. An implementation of the org.pi4soa.service.session.SessionManagerListener can be registered against the session manager to be informed when a new session has started or completed. The listener is also informed when a session begins to process an event, and when it either successfully or unsuccessfully finishes processing the event.

For example,


where the example class may be defined as:



            
public class MyExampleSessionMonitor implements SessionManagerListener {
 
    public MyExampleSessionMonitor() {
    }
 
    public void sessionStarted(Session session) {
        m_sessionCount++;
    }
 
    public void sessionProcessingStarted(Session session) {
    }
 
    public void sessionProcessingCompleted(Session session) {
    }
 
    public void sessionCompleted(Session session) {
        m_sessionCount--;
 
        if (m_sessionCount <= 0) {
            synchronized(this) {
                m_completed = true;
                this.notifyAll();
            }
        }
    }
 
    public void sessionProcessingFailed(Session session) {
    }
 
    public boolean isCompleted() {
        return(m_completed);
    }
 
    public void waitForCompletion() {
        synchronized(this) {
            try {
                 if (isCompleted() == false) {
                     this.wait();
                 }
            } catch(Exception e) {
                System.err.println("Error: "+e);
            }
        }
    }
 
    private boolean m_completed=false;
    private int m_sessionCount=0;
};
 
    

This example listener uses reference counting to work out when all initiated sessions have been completed and then notifies the waiting thread.