You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2015/08/24 08:30:23 UTC

svn commit: r1697319 - in /qpid/java/trunk/broker-plugins: management-http/src/main/java/org/apache/qpid/server/management/plugin/ management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/ management-http/src/main/java/org/apache/q...

Author: orudyy
Date: Mon Aug 24 06:30:22 2015
New Revision: 1697319

URL: http://svn.apache.org/r1697319
Log:
QPID-6707: [Java Broker] Kill the Broker on invocation of store mutation operation ending with ServerScopedRuntimeException

work by Lorenz Quack <qu...@gmail.com> and Alex Rudyy <or...@apache.org>

Added:
    qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/ExceptionHandlingFilter.java
Modified:
    qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
    qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
    qpid/java/trunk/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java

Modified: qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java?rev=1697319&r1=1697318&r2=1697319&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java (original)
+++ qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java Mon Aug 24 06:30:22 2015
@@ -43,6 +43,7 @@ import javax.servlet.http.HttpServletReq
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import org.apache.qpid.server.management.plugin.filter.ExceptionHandlingFilter;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Server;
@@ -239,6 +240,8 @@ public class HttpManagement extends Abst
         root.getServletContext().setAttribute(HttpManagementUtil.ATTR_BROKER, getBroker());
         root.getServletContext().setAttribute(HttpManagementUtil.ATTR_MANAGEMENT_CONFIGURATION, this);
 
+        root.addFilter(new FilterHolder(new ExceptionHandlingFilter()), "/*", EnumSet.allOf(DispatcherType.class));
+
         FilterHolder loggingFilter = new FilterHolder(new LoggingFilter());
         root.addFilter(loggingFilter, "/api/*", EnumSet.of(DispatcherType.REQUEST));
         root.addFilter(loggingFilter, "/service/*", EnumSet.of(DispatcherType.REQUEST));

Added: qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/ExceptionHandlingFilter.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/ExceptionHandlingFilter.java?rev=1697319&view=auto
==============================================================================
--- qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/ExceptionHandlingFilter.java (added)
+++ qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/ExceptionHandlingFilter.java Mon Aug 24 06:30:22 2015
@@ -0,0 +1,85 @@
+/*
+ * 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.qpid.server.management.plugin.filter;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.server.util.ServerScopedRuntimeException;
+
+public class ExceptionHandlingFilter implements Filter
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionHandlingFilter.class);
+
+    private Thread.UncaughtExceptionHandler _uncaughtExceptionHandler;
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException
+    {
+        _uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
+        if (_uncaughtExceptionHandler == null)
+        {
+            throw new IllegalStateException("no uncaught exception handler set");
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
+    {
+        try
+        {
+            filterChain.doFilter(servletRequest, servletResponse);
+        }
+        catch (ServerScopedRuntimeException | Error e)
+        {
+            if (_uncaughtExceptionHandler == null)
+            {
+                throw e;
+            }
+            _uncaughtExceptionHandler.uncaughtException(Thread.currentThread(), e);
+        }
+        catch (IOException | ServletException e)
+        {
+            LOGGER.debug("Exception in servlet '{}': ", ((HttpServletRequest)servletRequest).getRequestURI(), e);
+            throw e;
+        }
+        catch (RuntimeException e)
+        {
+            LOGGER.error("Unexpected exception in servlet '{}': ", ((HttpServletRequest)servletRequest).getRequestURI(), e);
+            throw e;
+        }
+    }
+
+    @Override
+    public void destroy()
+    {
+        // noop
+    }
+}

Modified: qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java?rev=1697319&r1=1697318&r2=1697319&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java (original)
+++ qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java Mon Aug 24 06:30:22 2015
@@ -38,6 +38,8 @@ import java.util.Set;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.Part;
@@ -354,7 +356,6 @@ public class RestServlet extends Abstrac
     @Override
     protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
     {
-        try
         {
             String[] pathInfoElements = getPathInfoElements(request);
             if (pathInfoElements != null && pathInfoElements.length == _hierarchy.length + 1)
@@ -420,10 +421,6 @@ public class RestServlet extends Abstrac
                         sendCachingHeaders);
             }
         }
-        catch (RuntimeException e)
-        {
-            setResponseStatus(request, response, e);
-        }
     }
 
     private boolean isSingleObjectRequest(HttpServletRequest request)
@@ -465,6 +462,21 @@ public class RestServlet extends Abstrac
         performCreateOrUpdate(request, response);
     }
 
+    @Override
+    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        try
+        {
+            super.service(request, response);
+        }
+        catch (IllegalArgumentException | IllegalConfigurationException | IllegalStateException | AccessControlException
+                | ExchangeExistsException | QueueExistsException | IntegrityViolationException
+                | IllegalStateTransitionException | NoClassDefFoundError e)
+        {
+            setResponseStatus(request, response, e);
+        }
+    }
+
     private void performCreateOrUpdate(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
     {
         response.setContentType("application/json");
@@ -474,7 +486,6 @@ public class RestServlet extends Abstrac
         boolean isPostToFullURL = isFullObjectURL && "POST".equalsIgnoreCase(request.getMethod());
         final String[] pathInfoElements = getPathInfoElements(request);
         boolean isOperation = pathInfoElements != null && pathInfoElements.length == _hierarchy.length + 1 && isPostToFullURL;
-        try
         {
             if(!isOperation)
             {
@@ -533,11 +544,6 @@ public class RestServlet extends Abstrac
                 doOperation(request, response);
             }
         }
-        catch (RuntimeException | NoClassDefFoundError e)
-        {
-            setResponseStatus(request, response, e);
-        }
-
     }
 
     private void doOperation(final HttpServletRequest request,
@@ -935,16 +941,28 @@ public class RestServlet extends Abstrac
                 }
                 responseCode = SC_UNPROCESSABLE_ENTITY;
             }
+            else if (e instanceof NoClassDefFoundError)
+            {
+                message = "Not found: " + message;
+                LOGGER.warn("Unexpected exception processing request ", e);
+            }
             else
             {
-                if (e instanceof NoClassDefFoundError)
+                // This should not happen
+                if (e instanceof RuntimeException)
                 {
-                    message = "Not found: " + message;
+                    throw (RuntimeException)e;
+                }
+                else if (e instanceof Error)
+                {
+                    throw (Error)e;
+                }
+                else
+                {
+                    throw new RuntimeException("Unexpected Exception", e);
                 }
-                LOGGER.warn("Unexpected exception processing request ", e);
             }
 
-
             sendJsonErrorResponse(request, response, responseCode, message);
 
         }
@@ -953,7 +971,6 @@ public class RestServlet extends Abstrac
     @Override
     protected void doDeleteWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
     {
-        try
         {
             Collection<ConfiguredObject<?>> allObjects = getObjects(request);
             if(allObjects != null)
@@ -971,10 +988,6 @@ public class RestServlet extends Abstrac
                 sendJsonErrorResponse(request, response, HttpServletResponse.SC_NOT_FOUND, "Not Found");
             }
         }
-        catch(RuntimeException e)
-        {
-            setResponseStatus(request, response, e);
-        }
     }
 
     @Override

Modified: qpid/java/trunk/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java?rev=1697319&r1=1697318&r2=1697319&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java (original)
+++ qpid/java/trunk/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java Mon Aug 24 06:30:22 2015
@@ -37,9 +37,11 @@ import javax.management.MBeanOperationIn
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
 import javax.management.RuntimeErrorException;
+import javax.management.RuntimeMBeanException;
 import javax.management.remote.MBeanServerForwarder;
 import javax.security.auth.Subject;
 
+import org.apache.qpid.server.util.ServerScopedRuntimeException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -59,6 +61,7 @@ public class MBeanInvocationHandlerImpl
     private static final Logger _logger = LoggerFactory.getLogger(MBeanInvocationHandlerImpl.class);
 
     private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate";
+    private final Thread.UncaughtExceptionHandler _uncaughtExceptionHandler;
     private MBeanServer _mbs;
 
     private final boolean _managementRightsInferAllAccess;
@@ -68,6 +71,11 @@ public class MBeanInvocationHandlerImpl
     {
         _managementRightsInferAllAccess = Boolean.valueOf(System.getProperty(BrokerProperties.PROPERTY_MANAGEMENT_RIGHTS_INFER_ALL_ACCESS, "true"));
         _broker = broker;
+        _uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
+        if (_uncaughtExceptionHandler == null)
+        {
+            throw new IllegalStateException("no uncaught exception handler set");
+        }
     }
 
     public static MBeanServerForwarder newProxyInstance(Broker<?> broker)
@@ -165,13 +173,12 @@ public class MBeanInvocationHandlerImpl
         }
         catch (InvocationTargetException e)
         {
-            Throwable targetException =  e.getCause();
-            logTargetException(method, args, targetException);
-            throw targetException;
+            handleTargetException(method, args, e.getCause());
+            throw e.getCause();
         }
     }
 
-    private void logTargetException(Method method, Object[] args, Throwable targetException)
+    private void handleTargetException(Method method, Object[] args, Throwable targetException)
     {
         Throwable error = null;
         if (targetException instanceof RuntimeErrorException)
@@ -190,6 +197,21 @@ public class MBeanInvocationHandlerImpl
         {
             _logger.error("Unexpected error occurred on invoking of " + method + " with arguments " + Arrays.toString(args), targetException);
         }
+
+        if (targetException instanceof ServerScopedRuntimeException)
+        {
+            error = targetException;
+        }
+        else if (targetException instanceof RuntimeMBeanException)
+        {
+            // unwrap RuntimeMBeanException
+            error = ((RuntimeMBeanException)targetException).getTargetException();
+        }
+
+        if (error instanceof Error || error instanceof ServerScopedRuntimeException)
+        {
+            _uncaughtExceptionHandler.uncaughtException(Thread.currentThread(), error);
+        }
     }
 
     private Object authoriseAndInvoke(final Method method, final Object[] args) throws Exception



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org