3 Replies Latest reply on Apr 9, 2008 12:27 PM by Mark Little

    Web Service Transactions Implementation: Configuring WS Addr

    Andrew Dinn Master

      Well, the good news is that I've just successfully converted my Web Service Transactions (WSCOOR/WSAT/WSBA 1.1) implementation over JaxWS which was running on Glassfish to run successfully on JBossWS native 3.0.1/AS 5.0.0.B4. So, thank you for delivering this latest release.

      There's not really any corresponding bad news but the port from Glassfish has thrown up an interesting issue regarding the combined use of WS AddressingProperties and W3CEndpointReference instances. The WS-T protocols require use of both these datatypes for the following reasons.

      WSCOOR services hand out endpoints to clients to provide access to related services; endpoints are configured with reference parameters which are automatically attached to service requests to identify the transaction context.

      The asynchronous messaging protocol requires clients and services to configure WSAddr MessageIds and validate WS-Addr RelatesTo properties in order to tie together certain sequences of messages. Services also need to specify the WSAddr Action associated with a request.

      So, at various points where a service request is performed the client needs to obtain a port from its endpoint and then configure the MessageIdand Action properties to be used for the resulting communication. Here is a typical bit of code which does this job:

       . . .
       CompletionInitiatorService service = getCompletionInitiatorService();
       CompletionInitiatorPortType port = service.getPort(endpointReference, CompletionInitiatorPortType.class);
       BindingProvider bindingProvider = (BindingProvider)port;
       List<Handler> customHandlerChain = new ArrayList<Handler>();
      
       /*
       * we have to add the JaxWS WSAddressingClientHandler because we cannot specify the WSAddressing feature
       */
       customHandlerChain.add(new WSAddressingClientHandler());
       bindingProvider.getBinding().setHandlerChain(customHandlerChain);
       Map<String, Object> requestContext = bindingProvider.getRequestContext();
       AddressingProperties requestProperties = (AddressingProperties)requestContext.get(JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES_OUTBOUND);
       // overlay supplied addressing properties on request properties
       AddressingHelper.installCallerProperties(addressingProperties, requestProperties);
       // we should not need to do this but currently JBossWS does not pick up the value in the addressing properties
       requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, requestProperties.getTo().getURI().toString());
       return port;
      


      Ignore the hand cranking of the WS Addressing handler and endpoint address property -- they are stop-gaps until the WSAddressing Feature is fully functional.

      Now, this works because I know that the call to getPort installs an AddressingProperties instance on the port under the outbound client addressing properties property of the request context. This instance is configured with the To address embedded in the W3CEndpointReference. It's ReferenceParameters field has also been initialised using the reference parameters embedded in the W3CEndpointReference. The call to AddressingHelper.installCallerProperties adds the Action and MessageId. It overlays non-null fields found in the supplied AddressingProperties instance, addressingProperties, onto requestProperties, the instance obtained from the port.

      Now, in the Glassfish implementation there was no client addressing properties instance on the request context, So, I had to install my own addressing properties in order to supply the MessageId and Action. This caused a problem because there was no To field specified in AddressingProperties (it's embedded in the opaque W3CEndpointReference so only the Glassfish implementation can get at it). Glassfish actually makes the address available using the endpoint address property -- the call to getPort installs this on the requestContext via the endpoint address property. It also somehow managed to install the reference parameters into the message but they were not available via the requestContext as far as I could see. So, I had to fetch the address from the requestContext and install it in my addressing properties before installing them i.e.

       . . .
       CompletionInitiatorService service = getCompletionInitiatorService();
       CompletionInitiatorPortType port = service.getPort(endpointReference, CompletionInitiatorPortType.class);
       BindingProvider bindingProvider = (BindingProvider)port;
       List<Handler> customHandlerChain = new ArrayList<Handler>();
      
       /*
       * we have to add the JaxWS WSAddressingClientHandler because we cannot specify the WSAddressing feature
       */
       customHandlerChain.add(new WSAddressingClientHandler());
       bindingProvider.getBinding().setHandlerChain(customHandlerChain);
       Map<String, Object> requestContext = bindingProvider.getRequestContext();
       String address = (String)requestContext.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
       try {
       addressingProperties.setTo(builder.newURI(address));
       } catch (URISyntaxException use) {
       // TODO -- log unexpected error here
       }
       requestContext.put(JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES, addressingProperties);
       return port;
      


      So, my question is how can I guarantee that this merging of the client and endpoint addressing properties will be performed correctly. I am obviously concerned about what happens with JBossWS-Metro/CXF and would hope that I can rely upon the first code example above working on these ports. If not then we need to establish some way of making this work. Also, it would be nice to know if there is supposed to be some sort of standard way of doing this. In the absence of any such standard I would be interested to know whether and how far this requirement was considered when defining the WS Addr and JaxWS specs and when implementing this for JBossWS.