You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by sc...@apache.org on 2008/07/16 14:20:42 UTC

svn commit: r677254 - in /webservices/axis2/trunk/java/modules/jaxws: src/org/apache/axis2/jaxws/ src/org/apache/axis2/jaxws/server/dispatcher/ src/org/apache/axis2/jaxws/utility/ test/org/apache/axis2/jaxws/utility/

Author: scheu
Date: Wed Jul 16 05:20:40 2008
New Revision: 677254

URL: http://svn.apache.org/viewvc?rev=677254&view=rev
Log:
AXIS2-3298
Contributor:Rich Scheuerle
Isolate the logging of caught exceptions from the web service in WebServiceExceptionLogger.
Unchecked exceptions are always logged as errors.
All exceptions are logged if debug is enabled.

Added:
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/WebServiceExceptionLogger.java
    webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/utility/WebServiceExceptionLoggerTests.java
Removed:
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/utility/FailureLogger.java
Modified:
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaBeanDispatcher.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaDispatcher.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/ProviderDispatcher.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/utility/JavaUtils.java

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java?rev=677254&r1=677253&r2=677254&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java Wed Jul 16 05:20:40 2008
@@ -49,4 +49,11 @@
         "org.apache.axis2.jaxws.enableJAXBPayloadStreaming";
     public static final String MEP_CONTEXT = 
         "org.apache.axis2.jaxws.handler.MEPContext";
+    
+    /**
+     * If a checked exception is thrown by the webservice's webmethod, then
+     * the name of the checked exception is placed in the outbound response context.
+     */
+    public static final String CHECKED_EXCEPTION =
+        "org.apache.axis2.jaxws.checkedException";
 }

Added: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/WebServiceExceptionLogger.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/WebServiceExceptionLogger.java?rev=677254&view=auto
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/WebServiceExceptionLogger.java (added)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/WebServiceExceptionLogger.java Wed Jul 16 05:20:40 2008
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.axis2.jaxws;
+
+import org.apache.axis2.jaxws.i18n.Messages;
+import org.apache.axis2.jaxws.utility.JavaUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Controls error logging of exceptions thrown by the WebService application (provider, impl, etc.)
+ * 
+ * This class logs errors for all non-checked exceptions.
+ * This class logs extensive debug information for all exceptions.
+ */
+public class WebServiceExceptionLogger {
+    private static final Log log = LogFactory.getLog(WebServiceExceptionLogger.class);
+    
+    /**
+     * Logs an error if the exception thrown by @WebMethod m is not a checked exception.
+     * If debug logging is enabled, all exceptions are logged.
+     * @param method
+     * @param throwable
+     * @param logFully (if true then the exception is logged, otherwise only the class and stack is logged)
+     * @param serviceImplClass class of service implementation
+     * @param serviceInstance 
+     * @param args Object[] arguments pass to method
+     */
+    public static void log(Method method, 
+                           Throwable throwable, 
+                           boolean logFully,
+                           Class serviceImplClass,
+                           Object serviceInstance,
+                           Object[] args) {
+        
+        // Must have debug or error logging enabled
+        if (!log.isDebugEnabled() && !log.isErrorEnabled()) {
+            return;
+        }
+        
+        // Get the root of the exception
+        Throwable rootT = null;
+        if (throwable instanceof InvocationTargetException) {
+            rootT = ((InvocationTargetException) throwable).getTargetException();
+        }
+        
+        
+        String name = rootT.getClass().getName();
+        String stack = stackToString(rootT);
+        
+        // Determine if this is a checked exception or non-checked exception
+        Class checkedException = JavaUtils.getCheckedException(rootT, method);
+        
+        if (checkedException == null) {
+            // Only log errors for non-checked exceptions
+            if (log.isErrorEnabled()) {
+                String text = "";
+                if (logFully) {
+                    text = Messages.getMessage("failureLogger", name, rootT.toString());
+                   
+                } else {
+                    text = Messages.getMessage("failureLogger", name, stack);
+                }
+                log.error(text);
+            }
+            
+        } 
+        
+        // Full logging if debug is enabled.
+        if (log.isDebugEnabled()) {
+            log.debug("Exception invoking a method of " + serviceImplClass.toString()
+                    + " of instance " + serviceInstance.toString());
+            log.debug("Exception type thrown: " + throwable.getClass().getName());
+            if (rootT != null) {
+                log.debug("Root Exception type thrown: " + rootT.getClass().getName());
+            }
+            if (checkedException != null) {
+                log.debug("The exception is an instance of checked exception: " + 
+                          checkedException.getName());
+            }
+            log.debug("Method = " + method.toGenericString());
+            for (int i = 0; i < args.length; i++) {
+                String value =
+                        (args[i] == null) ? "null"
+                                : args[i].getClass().toString();
+                log.debug(" Argument[" + i + "] is " + value);
+            }
+        }
+        return;
+        
+    }
+    
+    /**
+     * Get a string containing the stack of the specified exception
+     *
+     * @param e
+     * @return
+     */
+    private static String stackToString(Throwable e) {
+        java.io.StringWriter sw = new java.io.StringWriter();
+        java.io.BufferedWriter bw = new java.io.BufferedWriter(sw);
+        java.io.PrintWriter pw = new java.io.PrintWriter(bw);
+        e.printStackTrace(pw);
+        pw.close();
+        String text = sw.getBuffer().toString();
+        // Jump past the throwable
+        text = text.substring(text.indexOf("at"));
+        return text;
+    }
+    
+    
+}

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaBeanDispatcher.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaBeanDispatcher.java?rev=677254&r1=677253&r2=677254&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaBeanDispatcher.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaBeanDispatcher.java Wed Jul 16 05:20:40 2008
@@ -107,6 +107,7 @@
             return null;
         } else if (faultThrown) {
             response = createFaultResponse(mc, mc.getMessage().getProtocol(), fault);
+            setCheckedExceptionProperty(response, target, fault);
         } else {
             response = createResponse(mc, mc.getMessage().getProtocol(), methodInputParams, output);
         }

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaDispatcher.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaDispatcher.java?rev=677254&r1=677253&r2=677254&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaDispatcher.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/JavaDispatcher.java Wed Jul 16 05:20:40 2008
@@ -20,16 +20,17 @@
 package org.apache.axis2.jaxws.server.dispatcher;
 
 import org.apache.axis2.description.AxisOperation;
+import org.apache.axis2.jaxws.Constants;
+import org.apache.axis2.jaxws.WebServiceExceptionLogger;
 import org.apache.axis2.jaxws.ExceptionFactory;
 import org.apache.axis2.jaxws.core.MessageContext;
-import org.apache.axis2.jaxws.description.OperationDescription;
 import org.apache.axis2.jaxws.server.EndpointCallback;
 import org.apache.axis2.jaxws.server.EndpointInvocationContext;
 import org.apache.axis2.jaxws.server.InvocationHelper;
 import org.apache.axis2.jaxws.server.InvocationListener;
 import org.apache.axis2.jaxws.server.InvocationListenerBean;
 import org.apache.axis2.jaxws.utility.ClassUtils;
-import org.apache.axis2.jaxws.utility.FailureLogger;
+import org.apache.axis2.jaxws.utility.JavaUtils;
 import org.apache.axis2.transport.TransportUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -69,38 +70,23 @@
         return serviceImplClass;
     }
     
-    protected Object invokeTargetOperation(Method method, Object[] params) throws Throwable {
+    protected final Object invokeTargetOperation(Method method, Object[] args) throws Throwable {
         Object output = null;
         try {
-            output = method.invoke(serviceInstance, params);
+            output = method.invoke(serviceInstance, args);
         } catch (Throwable t) {
-            Throwable rootT = null;
-            if (t instanceof InvocationTargetException) {
-                rootT = ((InvocationTargetException) t).getTargetException();
-            }
-            
-            // Minimal Logging to aid servicability.
-            // Only the error and the stack is logged.
-            FailureLogger.logError((rootT != null) ? rootT : t, 
-                                   false);  
-            
-            // Full logging if debug is enabled.
-            if (log.isDebugEnabled()) {
-                log.debug("Exception invoking a method of " + serviceImplClass.toString()
-                        + " of instance " + serviceInstance.toString());
-                log.debug("Exception type thrown: " + t.getClass().getName());
-                if (rootT != null) {
-                    log.debug("Root Exception type thrown: " + rootT.getClass().getName());
-                }
-                log.debug("Method = " + method.toGenericString());
-                for (int i = 0; i < params.length; i++) {
-                    String value =
-                            (params[i] == null) ? "null"
-                                    : params[i].getClass().toString();
-                    log.debug(" Argument[" + i + "] is " + value);
-                }
-            }
             
+            // Delegate logging the exception to the WebServiceExceptionLogger.
+            // Users can specifiy debug tracing of the WebServiceExceptionLogger to see
+            // all exceptions.
+            // Otherwise the WebServiceExceptionLogger only logs errors for non-checked exceptions
+            WebServiceExceptionLogger.log(method, 
+                                          t,
+                                          false,
+                                          serviceImplClass,
+                                          serviceInstance,
+                                          args);
+                                                         
             throw t;
         }
         
@@ -172,6 +158,7 @@
                     // If a fault was thrown, we need to create a slightly different
                     // MessageContext, than in the response path.
                     response = createFaultResponse(request, fault);
+                    setCheckedExceptionProperty(response, method, fault);
                 } else {
                     if (log.isDebugEnabled()) {
                         log.debug("Async invocation of the endpoint was successful.  Creating response message.");
@@ -248,4 +235,26 @@
          }
     }
     
+    /**
+     * Determine if the thrown exception is a checked exception.
+     * If so, then set the name of the checked exception on the response context
+     * @param response MessageContext
+     * @param m Method
+     * @param t Throwable
+     */
+    protected static void setCheckedExceptionProperty(MessageContext response, Method m, Throwable t) {
+        // Get the root of the exception
+        if (t instanceof InvocationTargetException) {
+            t = ((InvocationTargetException) t).getTargetException();
+        }
+        
+        // Determine if the thrown exception is checked
+        Class checkedException = JavaUtils.getCheckedException(t, m);
+        
+        // Add the property
+        if (checkedException != null) {
+            response.setProperty(Constants.CHECKED_EXCEPTION, checkedException.getCanonicalName());
+        }
+    }
+    
 }

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/ProviderDispatcher.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/ProviderDispatcher.java?rev=677254&r1=677253&r2=677254&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/ProviderDispatcher.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/server/dispatcher/ProviderDispatcher.java Wed Jul 16 05:20:40 2008
@@ -124,8 +124,10 @@
         Throwable fault = null;
         Object[] input = new Object[] {param};
         Object responseParamValue = null;
+        Method target = null;
         try {
-            responseParamValue = invokeTargetOperation(getJavaMethod(), input);
+            target = getJavaMethod();
+            responseParamValue = invokeTargetOperation(target, input);
         } catch (Throwable e) {
             fault = ClassUtils.getRootCause(e);
             faultThrown = true;
@@ -137,6 +139,7 @@
             // If a fault was thrown, we need to create a slightly different
             // MessageContext, than in the response path.
             responseMsgCtx = createFaultResponse(request, fault);
+            setCheckedExceptionProperty(responseMsgCtx, target, fault);
         } else {
             responseMsgCtx = createResponse(request, input, responseParamValue);
         }

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/utility/JavaUtils.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/utility/JavaUtils.java?rev=677254&r1=677253&r2=677254&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/utility/JavaUtils.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/utility/JavaUtils.java Wed Jul 16 05:20:40 2008
@@ -22,6 +22,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
@@ -202,4 +203,25 @@
         text = replace(text, "at ", "DEBUG_FRAME = ");
         return text;
     }
+    
+    /**
+     * Get checked exception
+     * @param throwable Throwable
+     * @param method Method
+     * @return Class of the checked exception or null
+     */
+    public static Class getCheckedException(Throwable throwable, Method method) {
+        if (method == null) {
+            return null;
+        }
+        Class[] exceptions = method.getExceptionTypes();
+        if (exceptions != null) {
+            for (int i=0; i< exceptions.length; i++ ) {
+                if (exceptions[i].isAssignableFrom(throwable.getClass())) {
+                    return exceptions[i];
+                }
+            }
+        }
+        return null;
+    }
 }

Added: webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/utility/WebServiceExceptionLoggerTests.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/utility/WebServiceExceptionLoggerTests.java?rev=677254&view=auto
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/utility/WebServiceExceptionLoggerTests.java (added)
+++ webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/utility/WebServiceExceptionLoggerTests.java Wed Jul 16 05:20:40 2008
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.axis2.jaxws.utility;
+
+import org.apache.axis2.jaxws.WebServiceExceptionLogger;
+
+import java.awt.Image;
+import java.io.File;
+import java.lang.reflect.Method;
+
+import javax.imageio.ImageIO;
+import javax.xml.ws.wsaddressing.W3CEndpointReference;
+
+import junit.framework.TestCase;
+
+/**
+ * Validate the FailureLogger utility
+ */
+public class WebServiceExceptionLoggerTests extends TestCase {
+    /**
+     * Validate FailureLogger.getCheckedException method
+     * @throws Exception
+     */
+    public void testCheckedException() throws Exception {
+        
+        Method m = Sample.class.getMethod("m", new Class[] {});
+        
+        Throwable t = new ExceptionA();
+        Class checkedException = JavaUtils.getCheckedException(t, m);      
+        assertTrue(ExceptionA.class.equals(checkedException));
+        
+        t = new ExceptionB();
+        checkedException = JavaUtils.getCheckedException(t, m); 
+        assertTrue(ExceptionB.class.equals(checkedException));
+        
+        t = new ExceptionC();
+        checkedException = JavaUtils.getCheckedException(t, m); 
+        assertTrue(ExceptionB.class.equals(checkedException));
+        
+        t = new ExceptionD();
+        checkedException = JavaUtils.getCheckedException(t, m); 
+        assertTrue(checkedException == null);
+        
+        t = new NullPointerException();
+        checkedException = JavaUtils.getCheckedException(t, m); 
+        assertTrue(checkedException == null);
+        
+    }
+    
+    class Sample {
+        public void m() throws ExceptionA, ExceptionB {}
+    }
+    
+    class ExceptionA extends Exception {
+        
+    }
+    
+    class ExceptionB extends Exception {
+        
+    }
+    
+    class ExceptionC extends ExceptionB {
+        
+    }
+    
+    class ExceptionD extends Exception {
+        
+    }
+}