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 <[email protected]> and Alex Rudyy <[email protected]> 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: [email protected] For additional commands, e-mail: [email protected]
