Multiplexed EndpointReferences has been created by Gary Tully (Apr 20, 2007).

Content:

Support for Multiplexed EndpointReferences in CXF allows a single stateless service instance to represent/impersonate multiple service instances. The single service does not maintain any state itself, but instead uses attributes of the current target EndpointReference to identify instance data. The piggybacking of state in an EndpointReference is a form of applicaion level multiplexing.

To illustrate, consider a simple web service called Number that represents an integer and suports a single operation isEven that returns true iff the Number is even. Consider also a NumberFactory service that returns Endpoint References(EPRs) to Numbers through an operation create(int).

A typical implementation of NumberFactory.create() would instanciate and publish an endpoint for each requested integer value, returning the corresponding EPR to the caller. Given the infinite set of possible Number values, this implementation would scale poorly as the number of calls to create different values increase.

Enter multiplexed endpoint references. The implementation of NumberFactory.create() instanciates and publishes a single template service. Then for each unique value of Number, the implementation generates (using a CXF API) a multiplexed EPR for that particular value. This EPR is returned to the caller.

The implementation of the single template Number service needs a mechanism to determine its current state or value. It gets this from CXF based on the target EndpointReference. It then proceeds to determine if the current value is even and returns the result to the caller.

In this way, a single service instance can represent all possible Numbers, the only state is embedded in the multiplexed endpoint references that are maintained by the callers.

Here is skeleton implementation of NumberFactory.create():

EndpointReferenceType create(int val) {
   synchronized (this) {
     if (!servicePublished) {
        publishSingleInstanceServant(SERVICE_QNAME);
        servicePublished = true;
     }
   }
   String state = String.valueOf(val);
   String portName = null; // unless there are multiple ports in the service 
   return EndpointReferenceUtils.getEndpointReferenceWithId(SERVICE_QNAME, 
              portName, state, BusFactory.getDefaultBus()); 
 }

Here is the skeleton implementation of Number.isEven():

 

    @Resource
    protected WebServiceContext wsContext;
    
    public boolean isEven() {

        MessageContext messageContext = wsContext.getMessageContext();
        String state = EndpointReferenceUtils
            .getCurrentEndpointReferenceId(messageContext);
        
        int val = Integer.parseInt(state);
        return valIsEven(val);
    }
How does it Work

The API uses reference parameters to embedd the users state in an EndpointReference. The referece parameters are part of the EPR that is returned to the caller. WS-Addressing interceptors are used to propagate the reference parameters as a soap header on subsequent invocations using the returned EPR. On the receiving side, the current WS-Addressing MEPs are queried to extract the state from the reference parameters.

Working without WS-Addressing

WS-A provides a transport/protocol neutral approach to state transfer and is the default mechanism for multiplexing supported by CXF. However some transports, notably HTTP, have implicit support for mutiplexing in the form of contexts and query parameters. The CXF HTTP transport supports a multiplexWithAddress configuration attribute that when enabled, negates the use of WS-A and forces the state to be embedded in the URL context.

For example, in the Number scenario above, the single Number service endpoint would publish a URL of the form: http://host:port/NumberService/Number/ with a URL matching strategy of stem. A call to NumberFactory.create(22) would result in an EPR that contained the address element http://localhost:9080/NumberService/Number/22. In this way, the multiplex state becomes a natural part of the HTTP endpoint address URL which can be consumed by native HTTP clients.

Using EndpointRefernces with a JAX-WS Service

JAX-WS 2.0 provides APIs that allow a port to be created with an EPR. CXF is working towards JAX-WS 1.0 certification which is incompatable with JAX-WS 2.0. Thus in the short term, CXF will not expose the usefull JAX-WS 2.0 API. As an interm solution, CXF provides a utility class that allows a JAX-WS client to reference the underlying provider implementation object on which a getPort(EndpointReferenceType ..) method exists.

Sample JAX-WS client code would do the following to access a Number instance using an EPR -

 

    NumberFactoryService service = new NumberFactoryService();
    NumberFactory factory = service.getNumberFactoryPort();
        
    EndpointReferenceType epr = factory.create("20");
    NumberService numService = new NumberService();
    ServiceImpl serviceImpl = ServiceDelegateAccessor.get(numService);                   
    Number num = (Number)serviceImpl.getPort(epr, Number.class);
    ...

Reply via email to