You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@axis.apache.org by ba...@apache.org on 2011/04/25 19:22:44 UTC

svn commit: r1096530 - in /axis/axis2/java/core/trunk/modules: jaxws-integration/test/org/apache/axis2/jaxws/sample/ jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/ jaxws/src/org/apache/axis2/jaxws/ jaxws/src/org/apache/axis2/ja...

Author: barrettj
Date: Mon Apr 25 17:22:44 2011
New Revision: 1096530

URL: http://svn.apache.org/viewvc?rev=1096530&view=rev
Log:
On JAX-WS Client, treat local exceptions (e.g. ConnectException) as a SOAPFault, driving the JAX-WS handler handleFault methods and throwing a SOAPFAultException back through the client invocation.  Also provide a property to revert to previous behavior of creating an empty message, driving the JAX-WS handler handleMessage methods, and throwing a WebServiceException back through the client invocation.

Modified:
    axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java
    axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/AddNumbersClientLogicalHandler3.java
    axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java
    axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java
    axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java
    axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/core/controller/impl/AxisInvocationController.java
    axis/axis2/java/core/trunk/modules/metadata/src/org/apache/axis2/jaxws/ExceptionFactory.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=1096530&r1=1096529&r2=1096530&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 Apr 25 17:22:44 2011
@@ -27,6 +27,7 @@ import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.StringWriter;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Future;
@@ -45,6 +46,7 @@ import javax.xml.ws.BindingProvider;
 import javax.xml.ws.Dispatch;
 import javax.xml.ws.Response;
 import javax.xml.ws.Service;
+import javax.xml.ws.WebServiceException;
 import javax.xml.ws.handler.Handler;
 import javax.xml.ws.handler.HandlerResolver;
 import javax.xml.ws.handler.PortInfo;
@@ -53,7 +55,11 @@ import javax.xml.ws.soap.SOAPFaultExcept
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
+import org.apache.axis2.AxisFault;
+import org.apache.axis2.description.Parameter;
+import org.apache.axis2.engine.AxisConfiguration;
 import org.apache.axis2.jaxws.TestLogger;
+import org.apache.axis2.jaxws.description.ServiceDescription;
 import org.apache.axis2.jaxws.framework.AbstractTestCase;
 import org.apache.axis2.jaxws.sample.addnumbershandler.AddNumbersClientLogicalHandler;
 import org.apache.axis2.jaxws.sample.addnumbershandler.AddNumbersClientLogicalHandler2;
@@ -64,11 +70,14 @@ import org.apache.axis2.jaxws.sample.add
 import org.apache.axis2.jaxws.sample.addnumbershandler.AddNumbersHandlerPortType;
 import org.apache.axis2.jaxws.sample.addnumbershandler.AddNumbersHandlerService;
 import org.apache.axis2.jaxws.sample.addnumbershandler.AddNumbersProtocolHandler2;
+import org.apache.axis2.jaxws.spi.ServiceDelegate;
 import org.test.addnumbershandler.AddNumbersHandlerResponse;
 
 public class AddNumbersHandlerTests extends AbstractTestCase {
 	
     String axisEndpoint = "http://localhost:6060/axis2/services/AddNumbersHandlerService.AddNumbersHandlerPortTypeImplPort";
+    String invalidAxisEndpoint = "http://invalidHostName:6060/axis2/services/AddNumbersHandlerService.AddNumbersHandlerPortTypeImplPort";
+
     static File requestFile = null;
     static {
         String resourceDir = System.getProperty("basedir",".")+
@@ -568,7 +577,6 @@ public class AddNumbersHandlerTests exte
             
             fail("We should have got an exception due to the handler.");
         } catch(Exception e) {
-            e.printStackTrace();
             assertTrue("Exception should be SOAPFaultException", e instanceof SOAPFaultException);
             assertEquals(((SOAPFaultException)e).getMessage(), "I don't like the value 99");
             
@@ -828,7 +836,7 @@ public class AddNumbersHandlerTests exte
             
             String log = readLogFile();
             String expected_calls = "AddNumbersClientLogicalHandler4 HANDLE_MESSAGE_OUTBOUND\n"
-                + "AddNumbersClientLogicalHandler3 HANDLE_FAULT_OUTBOUND\n"
+                + "AddNumbersClientLogicalHandler3 HANDLE_MESSAGE_OUTBOUND\n"
                 + "AddNumbersClientLogicalHandler HANDLE_MESSAGE_OUTBOUND\n"
                 + "AddNumbersClientLogicalHandler3 HANDLE_FAULT_INBOUND\n"
                 + "AddNumbersClientLogicalHandler3 RETURNING FALSE INBOUND\n"
@@ -841,6 +849,103 @@ public class AddNumbersHandlerTests exte
         TestLogger.logger.debug("----------------------------------");
     }
 
+    /**
+     * Validate that a local exception (in this case a ConnectionException caused by an invalid
+     * host on the EPR) is returned as a SOAPFaultException, and the JAX-WS application handler 
+     * handleFault() methods are driven.  This is the default behavior.
+     */
+    public void testAddNumbersClientHandlerWithLocalException() {
+        try{
+            TestLogger.logger.debug("----------------------------------");
+            TestLogger.logger.debug("test: " + getName());
+            
+            AddNumbersHandlerService service = new AddNumbersHandlerService();
+            AddNumbersHandlerPortType proxy = service.getAddNumbersHandlerPort();
+            
+            BindingProvider p = (BindingProvider)proxy;
+
+            // Force a local connection exception by using an invalid host/port
+            p.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, invalidAxisEndpoint);
+
+            List<Handler> handlers = p.getBinding().getHandlerChain();
+            if (handlers == null)
+                handlers = new ArrayList<Handler>();
+            handlers.add(new AddNumbersClientLogicalHandler4());
+            handlers.add(new AddNumbersClientLogicalHandler2());
+            
+            p.getBinding().setHandlerChain(handlers);
+
+            int total = proxy.addNumbersHandler(1,2);
+            
+            fail("Should have got an exception, but we didn't.");
+        } catch(Exception e) {
+            assertTrue("Exception should be SOAPFaultException. Found " +e.getClass() + " "+ e.getMessage(), e instanceof SOAPFaultException);
+            SOAPFault soapFault = ((SOAPFaultException) e).getFault();
+            assertTrue("Cause should be instanceof UnknownHostException", (e.getCause() instanceof java.net.UnknownHostException));
+            
+            String log = readLogFile();
+            String expected_calls = "AddNumbersClientLogicalHandler4 HANDLE_MESSAGE_OUTBOUND\n"
+                + "AddNumbersClientLogicalHandler2 HANDLE_MESSAGE_OUTBOUND\n"
+                + "AddNumbersClientLogicalHandler2 HANDLE_FAULT_INBOUND\n"
+                + "AddNumbersClientLogicalHandler4 HANDLE_FAULT_INBOUND\n"
+                + "AddNumbersClientLogicalHandler2 CLOSE\n"
+                + "AddNumbersClientLogicalHandler4 CLOSE\n";
+            assertEquals(expected_calls, log);
+            
+        }
+        TestLogger.logger.debug("----------------------------------");
+    }
+
+    /**
+     * Validate that setting a property reverts the logic for how local exceptions are handled.
+     * Validate that a local exception (in this case a ConnectionException caused by an invalid
+     * host on the EPR) is returned as a WebServiceExcpetion (not a SOAPFaultException), and the 
+     * JAX-WS application handler handleMessage() methods are driven.
+     */
+    public void testAddNumbersClientHandlerWithLocalException_RevertBehaviorFlag() {
+        try{
+            TestLogger.logger.debug("----------------------------------");
+            TestLogger.logger.debug("test: " + getName());
+            
+            AddNumbersHandlerService service = new AddNumbersHandlerService();
+            setAxisConfigParameter(service, org.apache.axis2.jaxws.Constants.DISABLE_SOAPFAULT_FOR_LOCAL_EXCEPTION, 
+                    "true");
+            AddNumbersHandlerPortType proxy = service.getAddNumbersHandlerPort();
+            
+            BindingProvider p = (BindingProvider)proxy;
+
+            // Force a local connection exception by using an invalid host/port
+            p.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, invalidAxisEndpoint);
+
+            List<Handler> handlers = p.getBinding().getHandlerChain();
+            if (handlers == null)
+                handlers = new ArrayList<Handler>();
+            handlers.add(new AddNumbersClientLogicalHandler4());
+            handlers.add(new AddNumbersClientLogicalHandler2());
+            
+            p.getBinding().setHandlerChain(handlers);
+
+            int total = proxy.addNumbersHandler(1,2);
+            
+            fail("Should have got an exception, but we didn't.");
+        } catch(Exception e) {
+            assertTrue("Exception should be WebServiceException.", e instanceof WebServiceException);
+            assertFalse("Exception should not be SOAPFaultException.", e instanceof SOAPFaultException);
+            assertTrue("Cause should be instanceof UnknownHostException", (e.getCause() instanceof java.net.UnknownHostException));
+            
+            String log = readLogFile();
+            String expected_calls = "AddNumbersClientLogicalHandler4 HANDLE_MESSAGE_OUTBOUND\n"
+                + "AddNumbersClientLogicalHandler2 HANDLE_MESSAGE_OUTBOUND\n"
+                + "AddNumbersClientLogicalHandler2 HANDLE_MESSAGE_INBOUND\n"
+                + "AddNumbersClientLogicalHandler4 HANDLE_MESSAGE_INBOUND\n"
+                + "AddNumbersClientLogicalHandler2 CLOSE\n"
+                + "AddNumbersClientLogicalHandler4 CLOSE\n";
+            assertEquals(expected_calls, log);
+            
+        }
+        TestLogger.logger.debug("----------------------------------");
+    }
+
     public void testAddNumbersClientHandlerWithFalse() throws Exception {
         AddNumbersClientLogicalHandler2 clh = new AddNumbersClientLogicalHandler2();
         AddNumbersClientProtocolHandler  cph = new AddNumbersClientProtocolHandler();
@@ -964,6 +1069,72 @@ public class AddNumbersHandlerTests exte
         }
     }
     
+    /**
+     * Validate the behavior of a local exception regarding JAX-WS application handlers for an async
+     * callback invocation.  
+     * 
+     * IMPORTANT NOTE:  This is documenting the current behavior for an async callback invocation, which
+     * is different than a synchronous invocation.  For async callback, if a local exception occurs, the
+     * JAX-WS handlers are not invoked again, unlike for a synchronous invocation.  This behavior should
+     * probably be made consistent with the sync invocation flow through JAX-WS handlers.
+     * @see #testAddNumbersClientHandlerWithLocalException()
+     * @see #testAddNumbersClientHandlerWithLocalException_RevertBehaviorFlag()
+     * 
+     */
+    public void testAddNumbersClientHandlerWithLocalExceptionAsync_RevertBehavior() {
+        try{
+            TestLogger.logger.debug("----------------------------------");
+            TestLogger.logger.debug("test: " + getName());
+            
+            AddNumbersHandlerService service = new AddNumbersHandlerService();
+            AddNumbersHandlerPortType proxy = service.getAddNumbersHandlerPort();
+            
+            BindingProvider p = (BindingProvider)proxy;
+            
+            p.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, invalidAxisEndpoint);
+
+            List<Handler> handlers = p.getBinding().getHandlerChain();
+            if (handlers == null)
+                handlers = new ArrayList<Handler>();
+            handlers.add(new AddNumbersClientLogicalHandler4());
+            handlers.add(new AddNumbersClientLogicalHandler2());
+            p.getBinding().setHandlerChain(handlers);
+
+            
+            AddNumbersHandlerAsyncCallback callback = new AddNumbersHandlerAsyncCallback();
+            Future<?> future = proxy.addNumbersHandlerAsync(10, 10, callback);
+
+            while (!future.isDone()) {
+                Thread.sleep(1000);
+                TestLogger.logger.debug("Async invocation incomplete");
+            }
+            
+            int total = callback.getResponseValue();
+            assertEquals("Local exception should cause value to be 0", 0, total);
+            TestLogger.logger.debug("Total (after handler manipulation) = " + total);
+            
+            Exception exception = callback.getException();
+            assertNotNull("Exception should be set", exception);
+            
+            assertTrue("Exception should be ExecutionException.", exception instanceof java.util.concurrent.ExecutionException);
+            assertTrue("Cause should be Web Service Exception", exception.getCause() instanceof WebServiceException);
+
+            String log = readLogFile();
+            // IMPORTANT NOTE: Currently the JAX-WS handlers are not invoked after the local exception
+            // occurs trying to send the invocation.  This is not necessarily correct and is different than
+            // the flow through the JAX-WS handlers for synchronous invocation.  This test is validating CURRENT
+            // behavior, and not necessarily CORRECT behavior.
+            String expected_calls = "AddNumbersClientLogicalHandler4 HANDLE_MESSAGE_OUTBOUND\n"
+                + "AddNumbersClientLogicalHandler2 HANDLE_MESSAGE_OUTBOUND\n";
+            assertEquals(expected_calls, log);
+            
+            TestLogger.logger.debug("----------------------------------");
+        } catch(Exception e) {
+            e.printStackTrace();
+            fail(e.toString());
+        }
+    }
+    
     public void testAddNumbersHandlerHandlerResolver() {
         try {
             System.out.println("----------------------------------");
@@ -1221,4 +1392,49 @@ public class AddNumbersHandlerTests exte
         return null;
     }
 
+    // These two methods enable a test spy, using the ServiceDelegate retrieved from a Service
+    // instance.  The spy will allow an parameter to be set on the AxisConfig in order to unit test
+    // the property.  This is NOT the way properties should be set on the config outside of a unit test
+    // environment.  The correct way to set properties on the config is to specify them in the associated
+    // axis2.xml file.
+    static private void setAxisConfigParameter(Service service, String key, String value) {
+        ServiceDelegate delegate = getServiceDelegate(service);
+        ServiceDescription svcDesc = delegate.getServiceDescription();
+        AxisConfiguration axisConfig = svcDesc.getAxisConfigContext().getAxisConfiguration();
+        Parameter parameter = new Parameter(key, value);
+        try {
+            axisConfig.addParameter(parameter);
+        } catch (AxisFault e) {
+            fail("Unable to set Parameter on AxisConfig due to exception " + e);
+        } 
+    }
+    static private ServiceDelegate getServiceDelegate(Service service) {
+        // Need to get to the private Service._delegate field in order to get to the ServiceDescription to test
+        ServiceDelegate returnServiceDelegate = null;
+        try {
+            try {
+//                Field serviceDelgateField = service.getClass().getDeclaredFields()[0];
+                Field serviceDelgateField = service.getClass().getDeclaredField("delegate");
+                serviceDelgateField.setAccessible(true);
+                returnServiceDelegate = (ServiceDelegate) serviceDelgateField.get(service);
+            } catch (NoSuchFieldException e) {
+                // This may be a generated service subclass, so get the delegate from the superclass
+                Field serviceDelegateField = service.getClass().getSuperclass().getDeclaredField("delegate");
+                serviceDelegateField.setAccessible(true);
+                returnServiceDelegate = (ServiceDelegate) serviceDelegateField.get(service);
+            } 
+        } catch (SecurityException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (NoSuchFieldException e) { 
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        return returnServiceDelegate;
+    }
+
+
 }

Modified: axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/AddNumbersClientLogicalHandler3.java
URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/AddNumbersClientLogicalHandler3.java?rev=1096530&r1=1096529&r2=1096530&view=diff
==============================================================================
--- axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/AddNumbersClientLogicalHandler3.java (original)
+++ axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/sample/addnumbershandler/AddNumbersClientLogicalHandler3.java Mon Apr 25 17:22:44 2011
@@ -56,7 +56,7 @@ public class AddNumbersClientLogicalHand
 
     public boolean handleMessage(LogicalMessageContext messagecontext) {
         Boolean outbound = (Boolean) messagecontext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
-        tracker.handleFault(outbound);
+        tracker.handleMessage(outbound);
         return true;
     }
     

Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java
URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java?rev=1096530&r1=1096529&r2=1096530&view=diff
==============================================================================
--- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java (original)
+++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java Mon Apr 25 17:22:44 2011
@@ -232,4 +232,22 @@ public interface Constants {
      */
     public static final String  DISPATCH_CLIENT_OUTBOUND_RESOLUTION = "jaxws.dispatch.outbound.operation.resolution.enable"; 
 
+    /** 
+     * Context Property:
+     * Name: jaxws.soapfault.local.exceptions.disable
+     * Value: String "false" or "true"
+     * Default: null, which is interpreted as "false"
+     * Can be set on:
+     * - Axis Configuration, which affects all jax-ws clients
+     *
+     * Indicates if local exceptions encountered by a JAX-WS client should be turned into a SOAPFaultException
+     * and then call the appropriate JAX-WS application handlers handleFault()methods with that SOAPFault
+     * in the message.  This is new behavior, which is the default behavior indicated by this property not being
+     * set or having a value of "false".
+     * 
+     * The previous behavior was for local exceptions to be turned into a WebServiceException that was set
+     * on an empty response message.  The appropriate JAX-WS application handers handleMessage() methods would be
+     * called with that empty message.  Setting this property to "true" will revert to this behavior.
+     */
+    public static final String  DISABLE_SOAPFAULT_FOR_LOCAL_EXCEPTION = "jaxws.soapfault.local.exceptions.disable"; 
 }

Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java
URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java?rev=1096530&r1=1096529&r2=1096530&view=diff
==============================================================================
--- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java (original)
+++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java Mon Apr 25 17:22:44 2011
@@ -838,6 +838,11 @@ public abstract class BaseDispatch<T> ex
                 // 4.3.2 conformance bullet 1 requires a ProtocolException here
                 ProtocolException pe =
                     MethodMarshallerUtils.createSystemException(msg.getXMLFault(), msg);
+                if (msgCtx.getLocalException() != null) {
+                    // If a local exception occured, set it as the initial cause of the 
+                    // exception that will be returned
+                    ExceptionFactory.setInitialCause(pe, msgCtx.getLocalException());
+                }
                 return pe;
             } else if (msgCtx.getLocalException() != null) {
                 // use the factory, it'll throw the right thing:

Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java
URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java?rev=1096530&r1=1096529&r2=1096530&view=diff
==============================================================================
--- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java (original)
+++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java Mon Apr 25 17:22:44 2011
@@ -581,7 +581,11 @@ public class JAXWSProxyHandler extends B
                     log.debug("Throwing a fault of type: " + object.getClass().getName() +
                     " back to the clent.");
                 }
-
+                if (msgCtx.getLocalException() != null) {
+                    // If a local exception occured, set it as the initial cause of the 
+                    // exception that will be returned
+                    ExceptionFactory.setInitialCause((Throwable) object, msgCtx.getLocalException());
+                }
                 return (Throwable)object;
             } else if (msgCtx.getLocalException() != null) {
                 // use the factory, it'll throw the right thing:

Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/core/controller/impl/AxisInvocationController.java
URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/core/controller/impl/AxisInvocationController.java?rev=1096530&r1=1096529&r2=1096530&view=diff
==============================================================================
--- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/core/controller/impl/AxisInvocationController.java (original)
+++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/core/controller/impl/AxisInvocationController.java Mon Apr 25 17:22:44 2011
@@ -26,6 +26,8 @@ import org.apache.axis2.addressing.Endpo
 import org.apache.axis2.client.OperationClient;
 import org.apache.axis2.client.Options;
 import org.apache.axis2.client.ServiceClient;
+import org.apache.axis2.description.Parameter;
+import org.apache.axis2.engine.AxisConfiguration;
 import org.apache.axis2.jaxws.BindingProvider;
 import org.apache.axis2.jaxws.ExceptionFactory;
 import org.apache.axis2.jaxws.client.ClientUtils;
@@ -36,6 +38,8 @@ import org.apache.axis2.jaxws.client.dis
 import org.apache.axis2.jaxws.core.InvocationContext;
 import org.apache.axis2.jaxws.core.MessageContext;
 import org.apache.axis2.jaxws.description.OperationDescription;
+import org.apache.axis2.jaxws.description.builder.MDQConstants;
+import org.apache.axis2.jaxws.handler.HandlerChainProcessor;
 import org.apache.axis2.jaxws.i18n.Messages;
 import org.apache.axis2.jaxws.message.Message;
 import org.apache.axis2.jaxws.message.factory.MessageFactory;
@@ -140,22 +144,29 @@ public class AxisInvocationController ex
             response = new MessageContext(axisResponseMsgCtx);
             response.setMEPContext(request.getMEPContext());
 
-            // If the Message object is still null, then it's possible that a
-            // local AxisFault was thrown and we need to save it for later throwing
-            // We do not want to create a message and go through the whole handler or
-            // XMLFault processing because it's unnecessary.
-            // 
-            // Same is true if we get a valid non-fault server response but some jaxws
-            // client processing (a handler, perhaps) throws an exception.
-            // 
-            // If the response message itself is a fault message, let it pass through.
+            // If there was a local exception caught and either there is no response message 
+            // OR the response message exists but is not a fault, then set the local exception
+            // on the response and determine how to set the response message to correspond to
+            // the local exception
             if ((faultexception != null) && ((response.getMessage() == null)
                     || (!response.getMessage().isFault()))) {
-                MessageFactory factory =
-                        (MessageFactory)FactoryRegistry.getFactory(MessageFactory.class);
-                Message message = factory.create(request.getMessage().getProtocol());
-                response.setLocalException(faultexception);
-                response.setMessage(message);
+                // Unless this behavior is disabled, convert the local exception to SOAPFaultException
+                // and set it on the response message.  This will also cause the JAX-WS application handler
+                // handleFault() methods to be called.
+                if (!isSOAPFaultForLocalExceptionDisabled(response)) {
+                    HandlerChainProcessor.convertToFaultMessage(request.getMEPContext(), faultexception, 
+                            request.getMessage().getProtocol());
+                    response.setLocalException(faultexception);
+                } else {
+                    // The behavior was disabled, so instead of creating a SOAPFaultException
+                    // just create an empty message and set the local exception on it.  This will cause the
+                    // JAX-WS application handler handleMessage() methods to be called with the empty message.
+                    MessageFactory factory =
+                            (MessageFactory)FactoryRegistry.getFactory(MessageFactory.class);
+                    Message message = factory.create(request.getMessage().getProtocol());
+                    response.setLocalException(faultexception);
+                    response.setMessage(message);
+                }
             }
 
             // This assumes that we are on the ultimate execution thread
@@ -643,4 +654,44 @@ public class AxisInvocationController ex
         ThreadContextMigratorUtil
                 .performContextCleanup(Constants.THREAD_CONTEXT_MIGRATOR_LIST_ID, msgContext);
     }
+    
+    /**
+     * Answer if generation of SOAPFaultExceptions for local Exceptions should be disabled..  The default value
+     * is "false", meaning that if a local exception is encountered, a SOAPFaultException should be generated in
+     * the message AND the appropriate JAX-WS application handlers handleFault() methods should be called with
+     * that message. 
+     * 
+     * @param msgContext used to get the Axis2 Configuration Context to check for the property
+     * @return false if generating SOAPFaultExceptions for local exceptions should be be enabled (default)
+     *   true if it should be disabled.
+     */
+    private static boolean isSOAPFaultForLocalExceptionDisabled(MessageContext msgContext) {
+        boolean soapFaultDisabled = false;
+
+        String flagValue = null;
+        org.apache.axis2.context.MessageContext axis2MC = msgContext.getAxisMessageContext();
+        if (axis2MC != null && axis2MC.getConfigurationContext() != null 
+                && axis2MC.getConfigurationContext().getAxisConfiguration() != null ) {
+            AxisConfiguration axisConfig = axis2MC.getConfigurationContext().getAxisConfiguration();
+            Parameter parameter = axisConfig.getParameter(org.apache.axis2.jaxws.Constants.DISABLE_SOAPFAULT_FOR_LOCAL_EXCEPTION);
+            if (parameter != null) {
+                flagValue = (String) parameter.getValue();
+                if (log.isDebugEnabled()) {
+                    log.debug("Property set on configuration: " + org.apache.axis2.jaxws.Constants.DISABLE_SOAPFAULT_FOR_LOCAL_EXCEPTION 
+                            + " with value " + flagValue);
+                }
+            }
+    
+            // If the property was set, check the value.
+            if (flagValue != null) {
+                if ("false".equalsIgnoreCase(flagValue)) {
+                    soapFaultDisabled = false;
+                } else if ("true".equalsIgnoreCase(flagValue)) {
+                    soapFaultDisabled = true;
+                }
+            }
+        }
+        return soapFaultDisabled;
+    }
+
 }

Modified: axis/axis2/java/core/trunk/modules/metadata/src/org/apache/axis2/jaxws/ExceptionFactory.java
URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/metadata/src/org/apache/axis2/jaxws/ExceptionFactory.java?rev=1096530&r1=1096529&r2=1096530&view=diff
==============================================================================
--- axis/axis2/java/core/trunk/modules/metadata/src/org/apache/axis2/jaxws/ExceptionFactory.java (original)
+++ axis/axis2/java/core/trunk/modules/metadata/src/org/apache/axis2/jaxws/ExceptionFactory.java Mon Apr 25 17:22:44 2011
@@ -323,6 +323,27 @@ public class ExceptionFactory {
         pw.close();
         return sw.getBuffer().toString();
     }
-
+    
+    /**
+     * Give a target Throwable, set the initialCause Throwable as the initial cause on the target. 
+     * @param target The throwable on which to set the initial cause
+     * @param initialCause The initial cause to set on the target Throwable.
+     */
+    public static void setInitialCause(Throwable target, Throwable initialCause) {
+        if (target != null && initialCause != null) {
+            // Create a WebServiceException from the initialCause throwable.  This skips over things like
+            // AxisFault as a cause.  Set the result on the target throwable.
+            try {
+                WebServiceException localException = ExceptionFactory.makeWebServiceException(initialCause);
+                target.initCause(localException.getCause());
+            } catch (Throwable t) {
+                // If the cause had already been set, then it can't be set again; it throws an exception.
+                if (log.isDebugEnabled()) {
+                    log.debug("Caught exception trying to set initial cause on: " + target +".  Initial cause: " +
+                            initialCause + ".  Caught: " + t);
+                }
+            }
+        }
+    }
 }