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 application level multiplexing.

To illustrate, consider a simple web service called Number that represents an integer and supports 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 instantiate 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() instantiates 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 dynamically determine its current state or value at runtime. 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 WS-Addressing(WS-A) reference parameters to embed the users state in an EndpointReference. The reference parameters are part of the EPR that is returned to the caller. WS-A 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-A 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 multiplexing 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.

The multiplexWithAddress property for HTTP is enabled by adding the following to cxf.xml

 <bean name="<port name>.http-destination" abstract="true">
   <property name="multiplexWithAddress" value="true"/>
 </bean>

 <!-- or for all http ports (using a wildcard) -->
 <bean name="*" abstract="true" class="org.apache.cxf.transport.http_jetty.JettyHTTPDestination">
   <property name="multiplexWithAddress" value="true"/>
 </bean>
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 incompatible with JAX-WS 2.0. Thus in the short term, CXF will not expose the useful JAX-WS 2.0 API. As an interim solution, CXF provides a utility class ServiceDelegateAccessor 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);
    ...