You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fx-dev@ws.apache.org by di...@apache.org on 2004/08/09 18:36:19 UTC

cvs commit: ws-fx/addressing/src/org/apache/axis/message/addressing/handler AxisClientSideAddressingHandler.java AxisServerSideAddressingHandler.java GenericAxisHandler.java ServerSideAddressingHandler.java

dims        2004/08/09 09:36:19

  Added:       addressing/src/org/apache/axis/message/addressing/handler
                        AxisClientSideAddressingHandler.java
                        AxisServerSideAddressingHandler.java
                        GenericAxisHandler.java
                        ServerSideAddressingHandler.java
  Log:
  Contribution from Ian Springer <ia...@hp.com>
  ===================================================
  The attached classes are intended to replace the existing class
  AddressingHandler. They are in the following class hierarchies, which
  are designed to facilitate easy porting to any JAX-RPC container:
  
  AxisClientSideAddressingHandler extends ClientSideAddressingHandler
  extends AbstractAddressingHandler
  
  AxisServerSideAddressingHandler extends ServerSideAddressingHandler
  extends AbstractAddressingHandler
  
  AbstractAddressingHandler is an abstract base class containing
  functionality shared by server-side and client-side handlers.
  ClientSideAddressingHandler and ServerSideAddressingHandler are
  client-side and server-side JAX-RPC handlers, respectively, that should
  work within any JAX-RPC container. They contain a few methods that can
  be overridden by platform-specific subclasses to provide more robust
  functionality. AxisClientSideAddressingHandler and
  AxisServerSideAddressingHandler are subclasses of the platform-neutral
  handlers that implement the Axis Handler interface and that leverage
  some Axis-specific APIs in overridden methods.
  
  All platform-neutral classes are below the org.apache.ws.addressing
  package, and all Axis-specific classes are below
  org.apache.axis.message.addressing.handler.
  
  I've written unit tests that test the key methods - handleRequest() and
  handleResponse() - in the platform-neutral handlers.
  
  Additionally, I've written an interface and factory that allow one to
  easily plug in different UUID-generation impls. The platform-neutral
  handlers utilize the opensource JUG library as the UUID generator, but
  use refelction to avoid a compile-time dependency on it. The
  Axis-specific handlers utilize the UUID generator that comes with Axis.
  
  There are still a number of data structure classes and interfaces in
  Apache Addressing that use Axis-specific classes like MessageElement and
  URI. These could be refactored fairly easily to be platform-neutral.
  Once this is done, Apache Addressing will be a portable WS-Addressing
  implementation that can be deployed and utilized on any JAX-RPC
  container. I think this will broaden the project's user and developer
  base.
  
  ===================================================
  
  Revision  Changes    Path
  1.1                  ws-fx/addressing/src/org/apache/axis/message/addressing/handler/AxisClientSideAddressingHandler.java
  
  Index: AxisClientSideAddressingHandler.java
  ===================================================================
  /*
   * Copyright  2004 The Apache Software Foundation.
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  package org.apache.axis.message.addressing.handler;
  
  import org.apache.axis.AxisFault;
  import org.apache.axis.Handler;
  import org.apache.ws.addressing.handler.ClientSideAddressingHandler;
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  
  import javax.xml.namespace.QName;
  import javax.xml.rpc.handler.MessageContext;
  import java.util.Hashtable;
  import java.util.List;
  
  /**
   * Axis-specific client-side WS-Addressing handler.
   *
   * @author Davanum Srinivas (dims@yahoo.com)
   * @author Ian P. Springer
   */
  public class AxisClientSideAddressingHandler extends ClientSideAddressingHandler implements Handler
  {
  
     private GenericAxisHandler axisHelperHandler = new GenericAxisHandler( this );
  
     /**
      * @see org.apache.axis.Handler#init()
      */
     public void init()
     {
        axisHelperHandler.init();
     }
  
     /**
      * @see org.apache.axis.Handler#cleanup()
      */
     public void cleanup()
     {
        axisHelperHandler.cleanup();
     }
  
     /**
      * @see org.apache.axis.Handler#onFault(org.apache.axis.MessageContext)
      */
     public void onFault( MessageContext msgContext )
     {
        axisHelperHandler.onFault( (org.apache.axis.MessageContext) msgContext );
     }
  
     /**
      * @see org.apache.axis.Handler#canHandleBlock(javax.xml.namespace.QName)
      */
     public boolean canHandleBlock( QName qname )
     {
        return ( axisHelperHandler.canHandleBlock( qname ) );
     }
  
     /**
      * @see org.apache.axis.Handler#setOption(java.lang.String, java.lang.Object)
      */
     public void setOption( String name,
                            Object value )
     {
        axisHelperHandler.setOption( name, value );
     }
  
     /**
      * Set a default value for the given option: if the option is not already set, then set it. if the option is already set,
      * then do not set it.
      * <p/>
      * If this is called multiple times, the first with a non-null value if 'value' will set the default, remaining calls will
      * be ignored.
      * <p/>
      * Returns true if value set (by this call), otherwise false;
      */
     public boolean setOptionDefault( String name,
                                      Object value )
     {
        return axisHelperHandler.setOptionDefault( name, value );
     }
  
     /**
      * @see org.apache.axis.Handler#getOption(java.lang.String)
      */
     public Object getOption( String name )
     {
        return axisHelperHandler.getOption( name );
     }
  
     /**
      * @see org.apache.axis.Handler#getOptions()
      */
     public Hashtable getOptions()
     {
        return axisHelperHandler.getOptions();
     }
  
     /**
      * @see org.apache.axis.Handler#setOptions(java.util.Hashtable)
      */
     public void setOptions( Hashtable opts )
     {
        axisHelperHandler.setOptions( opts );
     }
  
     /**
      * @see org.apache.axis.Handler#setName(java.lang.String)
      */
     public void setName( String name )
     {
        axisHelperHandler.setName( name );
     }
  
     /**
      * @see org.apache.axis.Handler#getName()
      */
     public String getName()
     {
        return axisHelperHandler.getName();
     }
  
     /**
      * @see org.apache.axis.Handler#getDeploymentData(org.w3c.dom.Document)
      */
     public Element getDeploymentData( Document doc )
     {
        return axisHelperHandler.getDeploymentData( doc );
     }
  
     /**
      * @see org.apache.axis.Handler#getUnderstoodHeaders()
      */
     public List getUnderstoodHeaders()
     {
        return axisHelperHandler.getUnderstoodHeaders();
     }
  
     /**
      * @see org.apache.axis.Handler#generateWSDL(org.apache.axis.MessageContext)
      */
     public void generateWSDL( org.apache.axis.MessageContext msgContext ) throws AxisFault
     {
        axisHelperHandler.generateWSDL( msgContext );
     }
  
     /**
      * @see org.apache.axis.Handler#invoke(org.apache.axis.MessageContext)
      */
     public void invoke( org.apache.axis.MessageContext msgContext ) throws AxisFault
     {
        axisHelperHandler.invoke( msgContext );
     }
  
     /**
      * @see org.apache.axis.Handler#onFault(org.apache.axis.MessageContext)
      */
     public void onFault( org.apache.axis.MessageContext msgContext )
     {
        axisHelperHandler.onFault( msgContext );
     }
  
     /**
      * Use the UUID generator that comes with Axis.
      *
      * @return a UUID
      */
     protected String generateUUId()
     {
        return axisHelperHandler.generateUUId();
     }
  
     /**
      * Axis-specific impl of {@link org.apache.ws.addressing.handler.ClientSideAddressingHandler#getSOAPAction(javax.xml.rpc.handler.MessageContext)}.
      *
      * @param msgContext JAX-RPC message context
      *
      * @return the value of the SOAPAction HTTP header
      */
     protected String getSOAPAction( MessageContext msgContext )
     {
        org.apache.axis.MessageContext axisMsgContext = (org.apache.axis.MessageContext) msgContext;
        return axisMsgContext.getSOAPActionURI();
     }
  
     /**
      * Axis-specific impl of {@link org.apache.ws.addressing.handler.ClientSideAddressingHandler#setSOAPAction(javax.xml.rpc.handler.MessageContext,
           * String)}.
      *
      * @param msgContext JAX-RPC message context
      * @param actionURI  the SOAPAction URI to be set
      */
     protected void setSOAPAction( MessageContext msgContext, String actionURI )
     {
        org.apache.axis.MessageContext axisMsgContext = (org.apache.axis.MessageContext) msgContext;
        axisMsgContext.setUseSOAPAction( true );
        axisMsgContext.setSOAPActionURI( actionURI );
     }
  }
  
  
  
  1.1                  ws-fx/addressing/src/org/apache/axis/message/addressing/handler/AxisServerSideAddressingHandler.java
  
  Index: AxisServerSideAddressingHandler.java
  ===================================================================
  /*
   * Copyright  2004 The Apache Software Foundation.
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  package org.apache.axis.message.addressing.handler;
  
  import org.apache.axis.AxisFault;
  import org.apache.axis.Handler;
  import org.apache.axis.Message;
  import org.apache.axis.message.addressing.AddressingHeaders;
  import org.apache.axis.message.addressing.Constants;
  import org.apache.axis.message.addressing.EndpointReference;
  import org.apache.ws.addressing.handler.ServerSideAddressingHandler;
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  
  import javax.xml.namespace.QName;
  import javax.xml.rpc.Call;
  import javax.xml.rpc.JAXRPCException;
  import javax.xml.rpc.Service;
  import javax.xml.rpc.handler.MessageContext;
  import javax.xml.rpc.handler.soap.SOAPMessageContext;
  import javax.xml.soap.SOAPBody;
  import java.util.Hashtable;
  import java.util.List;
  
  /**
   * Axis-specific server-side WS-Addressing handler.
   *
   * @author Davanum Srinivas (dims@yahoo.com)
   * @author Ian P. Springer
   */
  public class AxisServerSideAddressingHandler extends ServerSideAddressingHandler implements Handler
  {
  
     private GenericAxisHandler axisHelperHandler = new GenericAxisHandler( this );
  
     /**
      * @see org.apache.axis.Handler#init()
      */
     public void init()
     {
        axisHelperHandler.init();
     }
  
     /**
      * @see org.apache.axis.Handler#cleanup()
      */
     public void cleanup()
     {
        axisHelperHandler.cleanup();
     }
  
     /**
      * @see org.apache.axis.Handler#onFault(org.apache.axis.MessageContext)
      */
     public void onFault( MessageContext msgContext )
     {
        axisHelperHandler.onFault( (org.apache.axis.MessageContext) msgContext );
     }
  
     /**
      * @see org.apache.axis.Handler#canHandleBlock(javax.xml.namespace.QName)
      */
     public boolean canHandleBlock( QName qname )
     {
        return ( axisHelperHandler.canHandleBlock( qname ) );
     }
  
     /**
      * @see org.apache.axis.Handler#setOption(java.lang.String, java.lang.Object)
      */
     public void setOption( String name,
                            Object value )
     {
        axisHelperHandler.setOption( name, value );
     }
  
     /**
      * Set a default value for the given option:
      * if the option is not already set, then set it.
      * if the option is already set, then do not set it.
      * <p/>
      * If this is called multiple times, the first with a non-null value
      * if 'value' will set the default, remaining calls will be ignored.
      * <p/>
      * Returns true if value set (by this call), otherwise false;
      */
     public boolean setOptionDefault( String name,
                                      Object value )
     {
        return axisHelperHandler.setOptionDefault( name, value );
     }
  
     /**
      * @see org.apache.axis.Handler#getOption(java.lang.String)
      */
     public Object getOption( String name )
     {
        return axisHelperHandler.getOption( name );
     }
  
     /**
      * @see org.apache.axis.Handler#getOptions()
      */
     public Hashtable getOptions()
     {
        return axisHelperHandler.getOptions();
     }
  
     /**
      * @see org.apache.axis.Handler#setOptions(java.util.Hashtable)
      */
     public void setOptions( Hashtable opts )
     {
        axisHelperHandler.setOptions( opts );
     }
  
     /**
      * @see org.apache.axis.Handler#setName(java.lang.String)
      */
     public void setName( String name )
     {
        axisHelperHandler.setName( name );
     }
  
     /**
      * @see org.apache.axis.Handler#getName()
      */
     public String getName()
     {
        return axisHelperHandler.getName();
     }
  
     /**
      * @see org.apache.axis.Handler#getDeploymentData(org.w3c.dom.Document)
      */
     public Element getDeploymentData( Document doc )
     {
        return axisHelperHandler.getDeploymentData( doc );
     }
  
     /**
      * @see org.apache.axis.Handler#getUnderstoodHeaders()
      */
     public List getUnderstoodHeaders()
     {
        return axisHelperHandler.getUnderstoodHeaders();
     }
  
     /**
      * @see org.apache.axis.Handler#generateWSDL(org.apache.axis.MessageContext)
      */
     public void generateWSDL( org.apache.axis.MessageContext msgContext ) throws AxisFault
     {
        axisHelperHandler.generateWSDL( msgContext );
     }
  
     /**
      * @see org.apache.axis.Handler#invoke(org.apache.axis.MessageContext)
      */
     public void invoke( org.apache.axis.MessageContext msgContext ) throws AxisFault
     {
        axisHelperHandler.invoke( msgContext );
     }
  
     /**
      * @see org.apache.axis.Handler#onFault(org.apache.axis.MessageContext)
      */
     public void onFault( org.apache.axis.MessageContext msgContext )
     {
        axisHelperHandler.onFault( msgContext );
     }
  
     /**
      * Use the UUID generator that comes with Axis.
      *
      * @return a UUID
      */
     protected String generateUUId()
     {
        return axisHelperHandler.generateUUId();
     }
  
     // TODO: not sure if overriding this method is even necessary.
     protected void forwardMessage( SOAPMessageContext soapMsgContext, EndpointReference endpointRef )
     {
        try
        {
           Service service = getService( soapMsgContext );
           Call call = service.createCall();
           call.setTargetEndpointAddress( endpointRef.getAddress().toString() );
           ( (org.apache.axis.client.Call) call ).setRequestMessage( (Message) soapMsgContext.getMessage() );
           AddressingHeaders addrHeaders = buildAddressingHeadersForMessageForward( soapMsgContext, endpointRef );
           call.setProperty( Constants.ENV_ADDRESSING_REQUEST_HEADERS, addrHeaders );
           configureCall( call, soapMsgContext );
           call.invoke( new Object[0] );
           SOAPBody responseBody = soapMsgContext.getMessage().getSOAPPart().getEnvelope().getBody();
           removeAllChildElements( responseBody );
        }
        catch ( Exception e )
        {
           throw new JAXRPCException( "Failed to forward SOAP message." );
        }
  
     }
  
     protected void setTargetService( SOAPMessageContext soapMsgContext, AddressingHeaders headers )
           throws Exception
     {
        org.apache.axis.MessageContext axisMsgContext = (org.apache.axis.MessageContext) soapMsgContext;
        // TODO: why is the below code necessary? - add comments
        if ( axisMsgContext.getService() == null &&
              axisMsgContext.getTargetService() == null )
        {
           axisMsgContext.setTargetService( getTargetServiceName( headers ) );
           // This is to ensure the SOAPEnvelope is rebuilt with the right type mappings and
           // MessageContext is set with the right properties.
           if ( axisMsgContext.getTargetService() != null )
           {
              ( (Message) axisMsgContext.getMessage() ).getSOAPPartAsString();
           }
        }
     }
  
     private AddressingHeaders buildAddressingHeadersForMessageForward( SOAPMessageContext soapMsgContext, EndpointReference endpointRef )
     {
        AddressingHeaders headers = null;
        if ( soapMsgContext != null )
        {
           headers = (AddressingHeaders) soapMsgContext.getProperty( Constants.ENV_ADDRESSING_RESPONSE_HEADERS );
        }
        if ( headers == null )
        {
           headers = new AddressingHeaders( endpointRef );
        }
        return headers;
     }
  
  }
  
  
  
  1.1                  ws-fx/addressing/src/org/apache/axis/message/addressing/handler/GenericAxisHandler.java
  
  Index: GenericAxisHandler.java
  ===================================================================
  /*
   * Copyright  2004 The Apache Software Foundation.
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  package org.apache.axis.message.addressing.handler;
  
  import org.apache.axis.AxisFault;
  import org.apache.axis.handlers.BasicHandler;
  import org.apache.axis.message.addressing.uuid.AxisUUIdGenerator;
  import org.apache.ws.addressing.uuid.UUIdGeneratorFactory;
  
  import javax.xml.rpc.JAXRPCException;
  import javax.xml.rpc.handler.Handler;
  
  /**
   * Helper class to which the Axis-specific JAX-RPC handlers in this package
   * can delegate methods defined in the Axis {@link org.apache.axis.Handler}
   * interface. This is one so that the Axis handler base class
   * {@link BasicHandler} can be leveraged.
   *
   * @author Ian P. Springer
   */
  class GenericAxisHandler extends BasicHandler
  {
  
     private Handler jaxRpcHandler;
  
     public GenericAxisHandler( Handler handler )
     {
        jaxRpcHandler = handler;
     }
  
     /**
      * Impl of {@link org.apache.axis.Handler#invoke(org.apache.axis.MessageContext)}
      * that delegates to either
      * JAX-RPC {@link Handler#handleRequest(javax.xml.rpc.handler.MessageContext)} or
      * JAX-RPC {@link Handler#handleResponse(javax.xml.rpc.handler.MessageContext)},
      * depending upon whether the handler chain pivot has been passed yet or not.
      */
     public void invoke( org.apache.axis.MessageContext msgContext ) throws AxisFault
     {
        if ( !msgContext.getPastPivot() )
        {
           jaxRpcHandler.handleRequest( msgContext );
        }
        else
        {
           jaxRpcHandler.handleResponse( msgContext );
        }
     }
  
     /**
      * Impl of {@link org.apache.axis.Handler#onFault(org.apache.axis.MessageContext)}
      * that delegates to
      * JAX-RPC {@link Handler#handleFault(javax.xml.rpc.handler.MessageContext)}.
      */
     public void onFault( org.apache.axis.MessageContext msgContext )
     {
        jaxRpcHandler.handleFault( msgContext );
     }
  
     /**
      * Use the UUID generator that comes with Axis.
      *
      * @return a UUID
      */
     String generateUUId()
     {
        try
        {
           return UUIdGeneratorFactory.createUUIdGenerator( AxisUUIdGenerator.class ).generateUUId();
        }
        catch ( RuntimeException re )
        {
           throw new JAXRPCException( "Failed to generate UUId using Axis UUId generator " + AxisUUIdGenerator.class.getName() + ".", re );
        }
     }
  
  }
  
  
  
  1.1                  ws-fx/addressing/src/org/apache/axis/message/addressing/handler/ServerSideAddressingHandler.java
  
  Index: ServerSideAddressingHandler.java
  ===================================================================
  /*
   * Copyright  2004 The Apache Software Foundation.
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  package org.apache.ws.addressing.handler;
  
  import org.apache.axis.message.addressing.Action;
  import org.apache.axis.message.addressing.AddressingHeaders;
  import org.apache.axis.message.addressing.AttributedURI;
  import org.apache.axis.message.addressing.Constants;
  import org.apache.axis.message.addressing.EndpointReference;
  import org.apache.axis.message.addressing.MessageID;
  import org.apache.axis.message.addressing.To;
  import org.apache.axis.message.addressing.util.AddressingUtils;
  import org.apache.axis.types.URI;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  import javax.xml.namespace.QName;
  import javax.xml.rpc.Call;
  import javax.xml.rpc.JAXRPCException;
  import javax.xml.rpc.ServiceException;
  import javax.xml.rpc.ServiceFactory;
  import javax.xml.rpc.handler.MessageContext;
  import javax.xml.rpc.handler.soap.SOAPMessageContext;
  import javax.xml.soap.Node;
  import javax.xml.soap.SOAPBody;
  import javax.xml.soap.SOAPConnection;
  import javax.xml.soap.SOAPConnectionFactory;
  import javax.xml.soap.SOAPElement;
  import javax.xml.soap.SOAPMessage;
  import javax.xml.transform.TransformerFactory;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  /**
   * A server-side JAX-RPC {@link javax.xml.rpc.handler.Handler} that extracts
   * WS-Addressing headers from incoming SOAP requests and inserts them into
   * outgoing SOAP responses.
   *
   * @author Davanum Srinivas (dims@yahoo.com)
   * @author Ian P. Springer <ia...@hp.com>
   */
  public class ServerSideAddressingHandler extends AbstractAddressingHandler
  {
  
     private static final Log LOG =
           LogFactory.getLog( ServerSideAddressingHandler.class.getName() );
  
     /**
      * thread local that gives each thread its own TransformerFactory (since it is not thread-safe)
      */
     public static ThreadLocal TRANSFORMER_FACTORY =
           new ThreadLocal()
           {
              protected synchronized Object initialValue()
              {
                 return TransformerFactory.newInstance();
              }
           };
  
     public boolean handleRequest( MessageContext msgContext )
     {
        SOAPMessageContext soapMsgContext = (SOAPMessageContext) msgContext;
        try
        {
           SOAPMessage msg = soapMsgContext.getMessage();
           if ( msg == null )
           {
              return CONTINUE_HANDLER_CHAIN_PROCESSING;
           }
           AddressingHeaders headers =
                 new AddressingHeaders( msg.getSOAPPart().getEnvelope(),
                       getActor(),
                       true,
                       isRemoveHeadersEnabled(),
                       false,
                       getReferencePropertyQNames() );
  
           msgContext.setProperty( Constants.ENV_ADDRESSING_REQUEST_HEADERS,
                 headers );
  
           // set the target service based on To header if it hasn't already been
           // determined.  NOTE: May want to add an option to override later.
           setTargetService( soapMsgContext, headers );
        }
        catch ( Exception e )
        {
           if ( LOG.isDebugEnabled() )
           {
              e.printStackTrace();
           }
           throw new JAXRPCException( "unexpected error in handleRequest()", e );
        }
        return CONTINUE_HANDLER_CHAIN_PROCESSING;
     }
  
     public boolean handleResponse( MessageContext msgContext )
     {
        SOAPMessageContext soapMsgContext = (SOAPMessageContext) msgContext;
        try
        {
           SOAPMessage msg = soapMsgContext.getMessage();
           if ( msg == null )
           {
              return CONTINUE_HANDLER_CHAIN_PROCESSING;
           }
  
           AddressingHeaders reqHeaders =
                 (AddressingHeaders) msgContext.getProperty( Constants.ENV_ADDRESSING_REQUEST_HEADERS );
  
           if ( reqHeaders == null )
           {
              // error?
              return CONTINUE_HANDLER_CHAIN_PROCESSING;
           }
           AddressingHeaders resHeaders =
                 AddressingUtils.getResponseHeaders( msgContext );
           resHeaders.setSetMustUnderstand( isMustUnderstandEnabled( msgContext ) );
           processFromHeader( reqHeaders, resHeaders );
           processActionHeader( reqHeaders, resHeaders );
           processToHeader( reqHeaders, resHeaders );
           processRelatesToHeader( reqHeaders, resHeaders );
           processMessageIdHeader( resHeaders );
           resHeaders.toEnvelope( msg.getSOAPPart().getEnvelope(), getActor() );
           processReplyToHeader( reqHeaders, soapMsgContext );
        }
        catch ( Exception e )
        {
           if ( LOG.isDebugEnabled() )
           {
              e.printStackTrace();
           }
           throw new JAXRPCException( "unexpected error in handleResponse()", e );
        }
        return CONTINUE_HANDLER_CHAIN_PROCESSING;
     }
  
     public boolean handleFault( MessageContext msgContext )
     {
        SOAPMessageContext soapMsgContext = (SOAPMessageContext) msgContext;
        try
        {
           AddressingHeaders reqHeaders =
                 (AddressingHeaders) msgContext.getProperty( Constants.ENV_ADDRESSING_REQUEST_HEADERS );
           if ( reqHeaders == null )
           {
              // error?
              return CONTINUE_HANDLER_CHAIN_PROCESSING;
           }
           AddressingHeaders resHeaders =
                 AddressingUtils.getResponseHeaders( msgContext );
           processFromHeader( reqHeaders, resHeaders );
           // set action for fault only with 04 spec. 03 spec unclear on that issue
           if ( Constants.NS_URI_ADDRESSING.equals( Constants.NS_URI_ADDRESSING_04 ) )
           {
              resHeaders.setAction( new Action( new URI( Constants.FAULT_ACTION ) ) );
           }
           addRelatesToHeader( reqHeaders, resHeaders );
           addMessageIdHeader( resHeaders );
           addAddressingHeadersToSOAPEnvelope( soapMsgContext, resHeaders );
           processFaultToHeader( reqHeaders, soapMsgContext );
        }
        catch ( Exception e )
        {
           if ( LOG.isDebugEnabled() )
           {
              e.printStackTrace();
           }
           throw new JAXRPCException( "unexpected error in handleFault()", e );
        }
        return CONTINUE_HANDLER_CHAIN_PROCESSING;
     }
  
     /**
      * Forward the SOAP message contained in the specified SOAP message context
      * on to the specified endpoint reference.
      *
      * @param soapMsgContext
      * @param endpointRef
      */
     protected void forwardMessage( SOAPMessageContext soapMsgContext, EndpointReference endpointRef )
     {
        try
        {
           SOAPConnection soapConn = SOAPConnectionFactory.newInstance().createConnection();
           soapConn.call( soapMsgContext.getMessage(), toURL( endpointRef.getAddress() ) );
           soapConn.close();
           SOAPBody responseBody = soapMsgContext.getMessage().getSOAPPart().getEnvelope().getBody();
           removeAllChildElements( responseBody );
        }
        catch ( Exception e )
        {
           throw new JAXRPCException( "Failed to forward SOAP message." );
        }
     }
  
     private URL toURL( AttributedURI addr )
           throws MalformedURLException
     {
        return new URL( addr.toString() );
     }
  
     /**
      * Override this method if you need something other than the default Service.<br>
      * The service returned by this method is used in creating the new Call object.
      * Something like: <br>
      * <pre>
      * Service service = getService(msgContext);
      * Call call = service.createCall()
      * call.setTargetEndpointAddress(toEndPointReference.getAddress().toString());
      * </pre>
      *
      * @param msgContext
      *
      * @return
      */
     protected javax.xml.rpc.Service getService( MessageContext msgContext ) throws ServiceException
     {
        return ServiceFactory.newInstance().createService( new QName( "" ) );
     }
  
     /**
      * Override this method to prepare the new call, for instance to add
      * properties from the old MessageContext that may be needed by other
      * handlers.
      *
      * @param call       Call object about to be invoked
      * @param oldContext MessageContext of the original request/response.
      */
     protected void configureCall( Call call, MessageContext oldContext )
     {
        return;  // intentionally empty
     }
  
     /**
      * Can be overridden by subclasses to customize how the wsa:to header is interpreted.
      */
     protected String getTargetServiceName( AddressingHeaders headers )
           throws Exception
     {
        To toURI = headers.getTo();
        if ( toURI == null )
        {
           return null;
        }
        String to = toURI.getPath();
        if ( to == null )
        {
           return null;
        }
        // set the target service
        return ( to.substring( to.lastIndexOf( '/' ) + 1 ) );
     }
  
     /**
      * Platform-specific subclasses can optionally implement this method.
      *
      * @param soapMsgContext
      * @param headers
      *
      * @throws Exception
      */
     protected void setTargetService( SOAPMessageContext soapMsgContext, AddressingHeaders headers )
           throws Exception
     {
        return;  // intentionally empty
     }
  
     private void processFromHeader( AddressingHeaders requestAddrHeaders, AddressingHeaders responseAddrHeaders )
     {
        EndpointReference fromEPR = responseAddrHeaders.getFrom();
        if ( fromEPR == null )
        {
           To toURI = requestAddrHeaders.getTo();
           if ( toURI != null )
           {
              fromEPR = new EndpointReference( toURI );
              fromEPR.setProperties( requestAddrHeaders.getReferenceProperties() );
              responseAddrHeaders.setFrom( fromEPR );
           }
        }
     }
  
     private void processActionHeader( AddressingHeaders requestAddrHeaders, AddressingHeaders responseAddrHeaders )
           throws URI.MalformedURIException
     {
        Action action = responseAddrHeaders.getAction();
        if ( action == null )
        {
           // not set - try request headers
           action = requestAddrHeaders.getAction();
           if ( action != null )
           {
              responseAddrHeaders.setAction( new Action( new URI( action.toString() +
                    "Response" ) ) );
           }
        }
     }
  
     private void processToHeader( AddressingHeaders requestAddrHeaders, AddressingHeaders responseAddrHeaders )
           throws URI.MalformedURIException
     {
        if ( responseAddrHeaders.getFrom() == null && requestAddrHeaders.getFrom() != null )
        {
           responseAddrHeaders.setTo( requestAddrHeaders.getFrom().getAddress() );
        }
        else
        {
           responseAddrHeaders.setTo( new To( Constants.NS_URI_ANONYMOUS ) );
        }
     }
  
     private void processRelatesToHeader( AddressingHeaders requestAddrHeaders, AddressingHeaders responseAddrHeaders )
           throws URI.MalformedURIException
     {
        MessageID msgID = requestAddrHeaders.getMessageID();
        if ( msgID != null )
        {
           responseAddrHeaders.addRelatesTo( msgID.toString(),
                 Constants.QNAME_RESPONSE );
        }
     }
  
     private void processMessageIdHeader( AddressingHeaders responseAddrHeaders )
           throws URI.MalformedURIException
     {
        responseAddrHeaders.setMessageID( createMessageID() );
     }
  
     private void processReplyToHeader( AddressingHeaders requestAddrHeaders, SOAPMessageContext soapMsgContext )
           throws Exception
     {
        EndpointReference replyTo = requestAddrHeaders.getReplyTo();
        if ( replyTo != null )
        {
           AttributedURI address = replyTo.getAddress();
           if ( address != null )
           {
              String uri = address.toString();
              if ( uri != null && !uri.equals( Constants.NS_URI_ANONYMOUS ) )
              {
                 forwardMessage( soapMsgContext, replyTo );
              }
           }
        }
     }
  
     private void addAddressingHeadersToSOAPEnvelope( SOAPMessageContext soapMsgContext, AddressingHeaders resHeaders )
           throws Exception
     {
        SOAPMessage msg = soapMsgContext.getMessage();
        if ( msg == null )
        {
           throw new JAXRPCException( "Unable to obtain response message from SOAP message context." );
        }
        resHeaders.toEnvelope( msg.getSOAPPart().getEnvelope() );
     }
  
     private void processFaultToHeader( AddressingHeaders reqHeaders, SOAPMessageContext soapMsgContext )
           throws Exception
     {
        EndpointReference faultTo = reqHeaders.getFaultTo();
        if ( faultTo != null )
        {
           AttributedURI address = faultTo.getAddress();
           if ( address != null && address.toString() != null )
           {
              forwardMessage( soapMsgContext, faultTo );
           }
        }
     }
  
     private void addRelatesToHeader( AddressingHeaders reqHeaders, AddressingHeaders resHeaders )
           throws URI.MalformedURIException
     {
        MessageID msgID;
        msgID = reqHeaders.getMessageID();
        if ( msgID != null )
        {
           resHeaders.addRelatesTo( msgID.toString(),
                 Constants.QNAME_RESPONSE );
        }
     }
  
     private void addMessageIdHeader( AddressingHeaders resHeaders )
           throws URI.MalformedURIException
     {
        MessageID msgID;
        msgID = new MessageID( new URI( "uuid:" + generateUUId() ) );
        resHeaders.setMessageID( msgID );
     }
  
     /**
      * Removes all child elements from the specified {@link javax.xml.soap.SOAPElement}.
      * NOTE: w
      */
     protected static void removeAllChildElements( SOAPElement soapElem )
     {
        Iterator iter = soapElem.getChildElements();
        // NOTE: Convert iterator to list to avoid ConcurrentModificationExceptions
        // caused by modifying items in an iterator during iteration
        List children = toList( iter );
        for ( int i = 0; i < children.size(); i++ )
        {
           Node child = (Node) children.get( i );
           if ( child.getParentElement() != null )
           {
              child.detachNode();
              child.recycleNode();
           }
        }
     }
  
     private static List toList( Iterator iter )
     {
        List list = new ArrayList();
        while ( iter.hasNext() )
        {
           list.add( iter.next() );
        }
        return list;
     }
  
  }