blob: 8e7b3c3e2aed1fdbb5715291c1099f65a8dc34bb [file] [log] [blame]
/*
*
* 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;
import java.security.AccessController;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import javax.security.auth.Subject;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.management.plugin.controller.ConverterHelper;
import org.apache.qpid.server.management.plugin.servlet.rest.NotFoundException;
import org.apache.qpid.server.model.AbstractConfiguredObject;
import org.apache.qpid.server.model.IllegalStateTransitionException;
import org.apache.qpid.server.model.IntegrityViolationException;
import org.apache.qpid.server.model.OperationTimeoutException;
import org.apache.qpid.server.util.ExternalServiceException;
import org.apache.qpid.server.util.ExternalServiceTimeoutException;
public class ManagementException extends RuntimeException
{
private static final int SC_UNPROCESSABLE_ENTITY = 422;
private static final Logger LOGGER = LoggerFactory.getLogger(ManagementException.class);
private final int _statusCode;
private final Map<String, String> _headers;
private ManagementException(final int statusCode,
final String message,
final Map<String, String> headers)
{
super(message);
_statusCode = statusCode;
_headers = headers;
}
private ManagementException(final int statusCode,
final String message,
final Throwable cause,
final Map<String, String> headers)
{
super(message, cause);
_statusCode = statusCode;
_headers = headers;
}
public int getStatusCode()
{
return _statusCode;
}
public Map<String, String> getHeaders()
{
return _headers;
}
public static ManagementException createNotFoundManagementException(final Exception e)
{
return new ManagementException(HttpServletResponse.SC_NOT_FOUND, e.getMessage(), e, null);
}
public static ManagementException createNotFoundManagementException(final String message)
{
return new ManagementException(HttpServletResponse.SC_NOT_FOUND, message, null);
}
public static ManagementException createGoneManagementException(final String message)
{
return new ManagementException(HttpServletResponse.SC_GONE, message, null);
}
public static ManagementException createUnprocessableManagementException(final String message)
{
return new ManagementException(SC_UNPROCESSABLE_ENTITY, message, null);
}
public static ManagementException createUnprocessableManagementException(final Exception e)
{
return new ManagementException(SC_UNPROCESSABLE_ENTITY, e.getMessage(), e, null);
}
private static ManagementException createConflictManagementException(final Exception e)
{
return new ManagementException(HttpServletResponse.SC_CONFLICT, e.getMessage(), e, null);
}
public static ManagementException createNotAllowedManagementException(final String message,
final Map<String, String> headers)
{
return new ManagementException(HttpServletResponse.SC_METHOD_NOT_ALLOWED, message, headers);
}
public static ManagementException createForbiddenManagementException(final String message)
{
return new ManagementException(HttpServletResponse.SC_FORBIDDEN, message, null);
}
public static ManagementException createForbiddenManagementException(final Exception e)
{
return new ManagementException(HttpServletResponse.SC_FORBIDDEN, e.getMessage(), e, null);
}
public static ManagementException createInternalServerErrorManagementException(final String message)
{
return new ManagementException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message, null);
}
public static ManagementException createInternalServerErrorManagementException(final String message,
final Exception e)
{
return new ManagementException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message, e, null);
}
private static ManagementException createBadGatewayManagementException(final String message,
final RuntimeException e)
{
return new ManagementException(HttpServletResponse.SC_BAD_GATEWAY, message, e, null);
}
private static ManagementException createGatewayTimeoutManagementException(final RuntimeException e)
{
return new ManagementException(HttpServletResponse.SC_GATEWAY_TIMEOUT, e.getMessage(), e, null);
}
public static ManagementException createBadRequestManagementException(final String message)
{
return new ManagementException(HttpServletResponse.SC_BAD_REQUEST, message, null);
}
public static ManagementException createBadRequestManagementException(final String message, final Throwable e)
{
return new ManagementException(HttpServletResponse.SC_BAD_REQUEST, message, e, null);
}
public static ManagementException toManagementException(final RuntimeException e,
final String categoryMapping,
final List<String> path)
{
if (e instanceof SecurityException)
{
LOGGER.debug("{}, sending {}", e.getClass().getName(), HttpServletResponse.SC_FORBIDDEN, e);
return createForbiddenManagementException(e);
}
else if (e instanceof AbstractConfiguredObject.DuplicateIdException
|| e instanceof AbstractConfiguredObject.DuplicateNameException
|| e instanceof IntegrityViolationException
|| e instanceof IllegalStateTransitionException)
{
return createConflictManagementException(e);
}
else if (e instanceof NotFoundException)
{
if (LOGGER.isTraceEnabled())
{
LOGGER.trace(e.getClass().getSimpleName() + " processing request", e);
}
return createNotFoundManagementException(e);
}
else if (e instanceof IllegalConfigurationException || e instanceof IllegalArgumentException)
{
LOGGER.warn("{} processing request {} from user '{}': {}",
e.getClass().getSimpleName(),
getRequestURI(path, categoryMapping),
getRequestPrincipals(),
e.getMessage());
Throwable t = e;
int maxDepth = 10;
while ((t = t.getCause()) != null && maxDepth-- != 0)
{
LOGGER.warn("... caused by " + t.getClass().getSimpleName() + " : " + t.getMessage());
}
if (LOGGER.isDebugEnabled())
{
LOGGER.debug(e.getClass().getSimpleName() + " processing request", e);
}
return createUnprocessableManagementException(e);
}
else if (e instanceof OperationTimeoutException)
{
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("Timeout during processing of request {} from user '{}'",
getRequestURI(path, categoryMapping),
getRequestPrincipals(),
e);
}
else
{
LOGGER.info("Timeout during processing of request {} from user '{}'",
getRequestURI(path, categoryMapping), getRequestPrincipals());
}
return createBadGatewayManagementException("Timeout occurred", e);
}
else if (e instanceof ExternalServiceTimeoutException)
{
LOGGER.warn("External request timeout ", e);
return createGatewayTimeoutManagementException(e);
}
else if (e instanceof ExternalServiceException)
{
LOGGER.warn("External request failed ", e);
return createBadGatewayManagementException(e.getMessage(), e);
}
else if (e instanceof ManagementException)
{
return (ManagementException)e;
}
else
{
LOGGER.warn("Unexpected Exception", e);
return createInternalServerErrorManagementException("Unexpected Exception", e);
}
}
public static ManagementException handleError(final Error e)
{
if (e instanceof NoClassDefFoundError)
{
LOGGER.warn("Unexpected exception processing request ", e);
return createBadRequestManagementException("Not found: " + e.getMessage(), e);
}
else
{
throw e;
}
}
public static String getRequestURI(final List<String> path, final String categoryMapping)
{
return categoryMapping + (categoryMapping.endsWith("/") ? "" : "/")
+ path.stream().map(ConverterHelper::encode).collect(Collectors.joining("/"));
}
private static String getRequestPrincipals()
{
final Subject subject = Subject.getSubject(AccessController.getContext());
if (subject == null)
{
return null;
}
final Set<Principal> principalSet = subject.getPrincipals();
return String.join("/",
principalSet.stream()
.map(Principal::getName)
.collect(Collectors.toCollection(TreeSet::new)));
}
}