Author: scheu
Date: Mon Oct 25 14:28:02 2010
New Revision: 1027138

URL: http://svn.apache.org/viewvc?rev=1027138&view=rev
Log:
AXIS2-4862
Contributor:Rich Scheuerle
Summary:
Fixed JAX-WS handler chain processing to propogate the (possibly edited) 
Message to the Axis2 MessageContext when the handler chain is reversed due to a 
"return false" from user's JAX-WS handler.   This ensures that the correct 
message is returned to the inbound handlers and client application.

Also noticed that the JAX-WS fault processing has a similar problem.  Fixed the 
code in that case too.

Also noticed that the JAX-WS fault processing is not examining the handler's 
message prior to making a new message.
This contradicts the specification.  I changed to the code to examine the 
current message and see if it is a fault.
If it is, then that fault is retained.
If not, then the thown protocol Exception is converted into a fault message and 
becomes the current message.

Modified:
    
axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java
    
axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java

Modified: 
axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java?rev=1027138&r1=1027137&r2=1027138&view=diff
==============================================================================
--- 
axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java
 (original)
+++ 
axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java
 Mon Oct 25 14:28:02 2010
@@ -823,7 +823,7 @@ public class AddNumbersHandlerTests exte
             fail("Should have got an exception, but we didn't.");
         } catch(Exception e) {
             e.printStackTrace();
-            assertTrue("Exception should be SOAPFaultException", e instanceof 
SOAPFaultException);
+            assertTrue("Exception should be SOAPFaultException. Found " 
+e.getClass() + " "+ e.getMessage(), e instanceof SOAPFaultException);
             assertEquals("I don't like the value 99", 
((SOAPFaultException)e).getMessage());
             
             String log = readLogFile();

Modified: 
axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java?rev=1027138&r1=1027137&r2=1027138&view=diff
==============================================================================
--- 
axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java
 (original)
+++ 
axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java
 Mon Oct 25 14:28:02 2010
@@ -19,9 +19,11 @@
 
 package org.apache.axis2.jaxws.handler;
 
+import org.apache.axis2.AxisFault;
 import org.apache.axis2.jaxws.Constants;
 import org.apache.axis2.jaxws.ExceptionFactory;
 import org.apache.axis2.jaxws.context.factory.MessageContextFactory;
+import org.apache.axis2.jaxws.core.MessageContext;
 import org.apache.axis2.jaxws.handler.factory.HandlerPostInvokerFactory;
 import org.apache.axis2.jaxws.handler.factory.HandlerPreInvokerFactory;
 import org.apache.axis2.jaxws.i18n.Messages;
@@ -30,6 +32,7 @@ import org.apache.axis2.jaxws.message.Me
 import org.apache.axis2.jaxws.message.Protocol;
 import org.apache.axis2.jaxws.message.XMLFault;
 import org.apache.axis2.jaxws.message.factory.MessageFactory;
+import org.apache.axis2.jaxws.message.util.MessageUtils;
 import org.apache.axis2.jaxws.message.util.XMLFaultUtils;
 import org.apache.axis2.jaxws.registry.FactoryRegistry;
 import org.apache.axis2.jaxws.utility.SAAJFactory;
@@ -278,30 +281,75 @@ public class HandlerChainProcessor {
         // were invoked prior to completion or exception throwing
         if (expectResponse) {
             if (result == FAILED) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Handler returned false...Start running the 
handlers in reverse");
+                }
+                // One of that handlers returned false, therefore the handler 
processing
+                // is stoped and the transport outbound will be avoided.
+                // This may be due to an exception or it may be due the 
customer intentionally
+                // preventing a message from flowing outbound.
+                
                 // we should only use callGenericHandlers_avoidRecursion in 
this case
                 // the message context is now an outbound message context,
                 // and should be marked as such so the SOAPHeadersAdapter will
                 // "install" with the correct property key.
-                mepCtx.getMessageContext().setOutbound(newDirection == 
Direction.OUT);
-                SOAPHeadersAdapter.install(mepCtx.getMessageContext());        
        
+                
+                // Get the MessageContext and switch its direction
+                MessageContext jaxwsMC = mepCtx.getMessageContext();
+                jaxwsMC.setOutbound(newDirection == Direction.OUT);
+                SOAPHeadersAdapter.install(jaxwsMC);                
                 callGenericHandlers_avoidRecursion(newStart, newEnd, 
newDirection);
+                
+                // Now we need to place the Message (which is the one edited 
by the handler)
+                // onto the Axis2 MC.  This is necessary because the Axis2 
response MC
+                // will be created from this MC and must have the correct 
message.
+                this.placeMessageOnAxis2MessageContext(jaxwsMC);
+                
+                // Now close the handlers
                 callCloseHandlers(newStart_inclusive, newEnd, newDirection);
+                if (log.isDebugEnabled()) {
+                    log.debug("Handler returned false...End running the 
handlers in reverse");
+                }
             } else if (result == PROTOCOL_EXCEPTION) {
                 try {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Handler threw ProtocolException...Start 
running the handlers in reverse");
+                    }
                     // the message context is now an outbound message context,
                     // and should be marked as such so the SOAPHeadersAdapter 
will
                     // "install" with the correct property key.
-                    mepCtx.getMessageContext().setOutbound(newDirection == 
Direction.OUT);
-                    SOAPHeadersAdapter.install(mepCtx.getMessageContext());
+                    
+                    // Get the MessageContext and switch its direction
+                    MessageContext jaxwsMC = mepCtx.getMessageContext();
+                    jaxwsMC.setOutbound(newDirection == Direction.OUT);
+                    SOAPHeadersAdapter.install(jaxwsMC);
+                    
+                    // Call the handlerFault methods on the handlers and also 
close the handlers
                     callGenericHandleFault(newStart, newEnd, newDirection);
+                    
+                    // Now we need to place the Message (which is the one 
edited by the handler)
+                    // onto the Axis2 MC.  This is necessary because the Axis2 
response MC
+                    // will be created from this MC and must have the correct 
message.
+                    this.placeMessageOnAxis2MessageContext(jaxwsMC);
+                    
+                    // Now close the handlers
                     callCloseHandlers(newStart_inclusive, newEnd, 
newDirection);
+                    if (log.isDebugEnabled()) {
+                        log.debug("Handler threw ProtocolException...End 
running the handlers in reverse");
+                    }
                 } catch (RuntimeException re) {
                     callCloseHandlers(newStart_inclusive, newEnd, 
newDirection);
                     throw re;
                 }
             } else if (result == OTHER_EXCEPTION) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Handler threw unanticipated Exception...Start 
handler closure");
+                }
                 callCloseHandlers(newStart_inclusive, newEnd, newDirection);
                 // savedException initialized in 
HandlerChainProcessor.handleMessage
+                if (log.isDebugEnabled()) {
+                    log.debug("Handler threw unanticipated Exception...End 
handler closure");
+                }
                 throw savedException;
             }
         } else { // everything was successful OR finished processing handlers
@@ -354,6 +402,42 @@ public class HandlerChainProcessor {
         return true;
     }
 
+    /**
+     * Called during reversal and exception processing to place the 
+     * current Message (edited by the Handlers) onto the MessageContext
+     * @param jaxwsMC
+     */
+    private void placeMessageOnAxis2MessageContext(MessageContext jaxwsMC) {
+        if (log.isDebugEnabled()) {
+            log.debug("start placeMessageOnAxis2MessageContext");
+        }
+        try {
+            org.apache.axis2.context.MessageContext mc = 
jaxwsMC.getAxisMessageContext();
+            if (mc != null) {
+                Message message = jaxwsMC.getMessage();
+                if (message != null) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Place the (perhaps new or edited) Message 
on the MessageContext");
+                    }
+                    MessageUtils.putMessageOnMessageContext(message, mc);
+                } else {
+                    if (log.isDebugEnabled()) {
+                        log.debug("There is no Message.  Message is not copied 
to the Axis2 MessageContext.");
+                    }
+                }
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug("Axis2 MessageContext is not available.  Message 
is not copied");
+                }
+            }
+        } catch (AxisFault e) {
+            throw ExceptionFactory.makeWebServiceException(e);
+        } 
+        if (log.isDebugEnabled()) {
+            log.debug("end placeMessageOnAxis2MessageContext");
+        }
+    }
+    
     /*
       * callGenericHandlers_avoidRecursion should ONLY be called from one 
place.
       * TODO:  We cannot necessarily assume no false returns and no exceptions 
will be
@@ -437,7 +521,7 @@ public class HandlerChainProcessor {
                 
currentMC.put(javax.xml.ws.handler.MessageContext.MESSAGE_OUTBOUND_PROPERTY,
                                 (direction != Direction.OUT));
             if (ProtocolException.class.isAssignableFrom(re.getClass())) {
-                convertToFaultMessage(mepCtx, re, proto);
+                convertToFaultMessage(mepCtx, re, proto, true);
                 // just re-initialize the current handler message context since
                 // that will pick up the now-changed message
                 return PROTOCOL_EXCEPTION;
@@ -526,7 +610,9 @@ public class HandlerChainProcessor {
                 callGenericHandleFault(handlers.size() - 1, 0, direction);
             }
         } catch (RuntimeException re) {
-            // TODO: log it
+            if (log.isDebugEnabled()) {
+                log.debug("An exception occurred during handleFault chain 
processing", re);
+            }
             throw re;
         } finally {
             // we can close all the Handlers in reverse order
@@ -583,20 +669,43 @@ public class HandlerChainProcessor {
         }
     }
 
-
     public static void convertToFaultMessage(MEPContext mepCtx, Exception e, 
Protocol protocol) {
+        convertToFaultMessage(mepCtx, e, protocol, false);
+    }
+    
+    /**
+     * Converts the Exception into an XML Fault Message that is stored on the 
MEPContext.
+     * Note that if the forceConversion flag is true, this conversion will 
always occur.
+     * If the checkMsg flag is true, this conversion only occurs if the 
Message is not already
+     * a Fault (per 9,3,2.1 of the JAX-WS specification)
+     * 
+     * @param mepCtx  MEPContext
+     * @param e Exception
+     * @param protocol Protocol
+     * @param forceConversion  If true, the Exception is always converted to a 
Message
+     */
+    public static void convertToFaultMessage(MEPContext mepCtx, 
+            Exception e, 
+            Protocol protocol, 
+            boolean checkMsg) {
 
         // need to check if message is already a fault message or not,
         // probably by way of a flag (isFault) in the MessageContext or Message
         if (log.isDebugEnabled()) {
-            log.debug("Creating a fault Message object for the exception: " + 
e.getClass().getName());
+            log.debug("start convertToFaultMessge with exception: " + 
e.getClass().getName());
         }
            
         try {
-            /* TODO TODO TODO
-             * There has GOT to be a better way to do this.
-             */
-            if (protocol == Protocol.soap11 || protocol == Protocol.soap12) {
+            // According to the 9.3.2.1, The message is converted into a fault 
only if it is not already a Fault
+            Message messageFromHandler = 
mepCtx.getMessageContext().getMessage();
+            if (messageFromHandler != null && messageFromHandler.isFault()) {
+                if (log.isDebugEnabled()) {
+                    log.debug("The Message is already a SOAPFault.  The 
exception is not converted into a Message");
+                }
+            } else if (protocol == Protocol.soap11 || protocol == 
Protocol.soap12) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Converting Exception into a Message");
+                }
                 String protocolNS = (protocol == Protocol.soap11) ?
                         SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE :
                         SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE;
@@ -609,19 +718,24 @@ public class HandlerChainProcessor {
                 SOAPBody body = message.getSOAPBody();
                 SOAPFault soapFault = XMLFaultUtils.createSAAJFault(xmlFault, 
body);
 
-                // TODO something is wrong here.  The message should be a 
response message, not
-                // a request message.  I don't see how to change that.  (see 
the debugger...)
-                // TODO probably also need to turn on 
message.WRITE_XML_DECLARATION
                 MessageFactory msgFactory = (MessageFactory) 
FactoryRegistry.getFactory(MessageFactory.class);
                 Message msg = msgFactory.createFrom(message);
                 mepCtx.setMessage(msg);
 
             } else {
-                throw 
ExceptionFactory.makeWebServiceException(Messages.getMessage("cFaultMsgErr"));
+                WebServiceException wse = 
ExceptionFactory.makeWebServiceException(Messages.getMessage("cFaultMsgErr"));
+                if (log.isDebugEnabled()) {
+                    log.debug("end convertToFaultMessge due to error ", wse);
+                }
+                throw wse;
             }
 
         } catch (Exception ex) {
-            throw ExceptionFactory.makeWebServiceException(ex);
+            WebServiceException wse 
=ExceptionFactory.makeWebServiceException(ex);
+            if (log.isDebugEnabled()) {
+                log.debug("end convertToFaultMessge due to error ", wse);
+            }
+            throw wse;
         }
 
     }


Reply via email to