All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException Maven / Gradle / Ivy

There is a newer version: 7.4.5
Show newest version
/*
 * #%L
 * HAPI FHIR - Core Library
 * %%
 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
 * %%
 * Licensed 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.
 * #L%
 */
package ca.uhn.fhir.rest.server.exceptions;

import ca.uhn.fhir.i18n.Msg;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Base class for RESTful client and server exceptions. RESTful client methods will only throw exceptions which are subclasses of this exception type, and RESTful server methods should also only call
 * subclasses of this exception type.
 * 

* HAPI provides a number of subclasses of BaseServerResponseException, and each one corresponds to a specific * HTTP status code. For example, if a IResourceProvider method throws * {@link ResourceNotFoundException}, this is a signal to the server that an HTTP 404 should * be returned to the client. *

*

* See: A complete list of available exceptions is in the package summary. * If an exception doesn't exist for a condition you want to represent, let us know by filing an * issue in our tracker. You may also * use {@link UnclassifiedServerFailureException} to represent any error code you want. *

*/ public abstract class BaseServerResponseException extends RuntimeException { private static final Map> ourStatusCodeToExceptionType = new HashMap>(); private static final long serialVersionUID = 1L; static { registerExceptionType(PayloadTooLargeException.STATUS_CODE, PayloadTooLargeException.class); registerExceptionType(AuthenticationException.STATUS_CODE, AuthenticationException.class); registerExceptionType(InternalErrorException.STATUS_CODE, InternalErrorException.class); registerExceptionType(InvalidRequestException.STATUS_CODE, InvalidRequestException.class); registerExceptionType(MethodNotAllowedException.STATUS_CODE, MethodNotAllowedException.class); registerExceptionType(NotImplementedOperationException.STATUS_CODE, NotImplementedOperationException.class); registerExceptionType(NotModifiedException.STATUS_CODE, NotModifiedException.class); registerExceptionType(ResourceNotFoundException.STATUS_CODE, ResourceNotFoundException.class); registerExceptionType(ResourceGoneException.STATUS_CODE, ResourceGoneException.class); registerExceptionType(PreconditionFailedException.STATUS_CODE, PreconditionFailedException.class); registerExceptionType(ResourceVersionConflictException.STATUS_CODE, ResourceVersionConflictException.class); registerExceptionType(UnprocessableEntityException.STATUS_CODE, UnprocessableEntityException.class); registerExceptionType(ForbiddenOperationException.STATUS_CODE, ForbiddenOperationException.class); } private List myAdditionalMessages = null; private IBaseOperationOutcome myBaseOperationOutcome; private String myResponseBody; private Map> myResponseHeaders; private String myResponseMimeType; private int myStatusCode; private boolean myErrorMessageTrusted; /** * Constructor * * @param theStatusCode The HTTP status code corresponding to this problem * @param theMessage The message */ public /** * Interceptor hook method. This method should not be called directly. */ BaseServerResponseException(int theStatusCode, String theMessage) { super(theMessage); myStatusCode = theStatusCode; myBaseOperationOutcome = null; } /** * Constructor * * @param theStatusCode The HTTP status code corresponding to this problem * @param theMessages The messages */ public BaseServerResponseException(int theStatusCode, String... theMessages) { super(theMessages != null && theMessages.length > 0 ? theMessages[0] : null); myStatusCode = theStatusCode; myBaseOperationOutcome = null; if (theMessages != null && theMessages.length > 1) { myAdditionalMessages = Arrays.asList(Arrays.copyOfRange(theMessages, 1, theMessages.length, String[].class)); } } /** * Constructor * * @param theStatusCode The HTTP status code corresponding to this problem * @param theMessage The message * @param theBaseOperationOutcome An BaseOperationOutcome resource to return to the calling client (in a server) or the BaseOperationOutcome that was returned from the server (in a client) */ public BaseServerResponseException( int theStatusCode, String theMessage, IBaseOperationOutcome theBaseOperationOutcome) { super(theMessage); myStatusCode = theStatusCode; myBaseOperationOutcome = theBaseOperationOutcome; } /** * Constructor * * @param theStatusCode The HTTP status code corresponding to this problem * @param theMessage The message * @param theCause The cause */ public BaseServerResponseException(int theStatusCode, String theMessage, Throwable theCause) { super(theMessage, theCause); myStatusCode = theStatusCode; myBaseOperationOutcome = null; } /** * Constructor * * @param theStatusCode The HTTP status code corresponding to this problem * @param theMessage The message * @param theCause The underlying cause exception * @param theBaseOperationOutcome An BaseOperationOutcome resource to return to the calling client (in a server) or the BaseOperationOutcome that was returned from the server (in a client) */ public BaseServerResponseException( int theStatusCode, String theMessage, Throwable theCause, IBaseOperationOutcome theBaseOperationOutcome) { super(theMessage, theCause); myStatusCode = theStatusCode; myBaseOperationOutcome = theBaseOperationOutcome; } /** * Constructor * * @param theStatusCode The HTTP status code corresponding to this problem * @param theCause The underlying cause exception */ public BaseServerResponseException(int theStatusCode, Throwable theCause) { super(theCause.getMessage(), theCause); myStatusCode = theStatusCode; myBaseOperationOutcome = null; } /** * Constructor * * @param theStatusCode The HTTP status code corresponding to this problem * @param theCause The underlying cause exception * @param theBaseOperationOutcome An BaseOperationOutcome resource to return to the calling client (in a server) or the BaseOperationOutcome that was returned from the server (in a client) */ public BaseServerResponseException( int theStatusCode, Throwable theCause, IBaseOperationOutcome theBaseOperationOutcome) { super(theCause.toString(), theCause); myStatusCode = theStatusCode; myBaseOperationOutcome = theBaseOperationOutcome; } /** * This flag can be used to signal to server infrastructure that the message supplied * to this exception (ie to the constructor) is considered trusted and is safe to * return to the calling client. */ public boolean isErrorMessageTrusted() { return myErrorMessageTrusted; } /** * This flag can be used to signal to server infrastructure that the message supplied * to this exception (ie to the constructor) is considered trusted and is safe to * return to the calling client. */ public BaseServerResponseException setErrorMessageTrusted(boolean theErrorMessageTrusted) { myErrorMessageTrusted = theErrorMessageTrusted; return this; } /** * Add a header which will be added to any responses * * @param theName The header name * @param theValue The header value * @return Returns a reference to this for easy method chaining * @since 2.0 */ public BaseServerResponseException addResponseHeader(String theName, String theValue) { Validate.notBlank(theName, "theName must not be null or empty"); Validate.notBlank(theValue, "theValue must not be null or empty"); if (getResponseHeaders().containsKey(theName) == false) { getResponseHeaders().put(theName, new ArrayList<>()); } getResponseHeaders().get(theName).add(theValue); return this; } public List getAdditionalMessages() { return myAdditionalMessages; } /** * Returns the {@link IBaseOperationOutcome} resource if any which was supplied in the response, or null */ public IBaseOperationOutcome getOperationOutcome() { return myBaseOperationOutcome; } /** * Sets the BaseOperationOutcome resource associated with this exception. In server implementations, this is the OperartionOutcome resource to include with the HTTP response. In client * implementations you should not call this method. * * @param theBaseOperationOutcome The BaseOperationOutcome resource Sets the BaseOperationOutcome resource associated with this exception. In server implementations, this is the OperartionOutcome resource to include * with the HTTP response. In client implementations you should not call this method. */ public void setOperationOutcome(IBaseOperationOutcome theBaseOperationOutcome) { myBaseOperationOutcome = theBaseOperationOutcome; } /** * In a RESTful client, this method will be populated with the body of the HTTP respone if one was provided by the server, or null otherwise. *

* In a restful server, this method is currently ignored. *

*/ public String getResponseBody() { return myResponseBody; } /** * This method is currently only called internally by HAPI, it should not be called by user code. */ public void setResponseBody(String theResponseBody) { myResponseBody = theResponseBody; } /** * Returns a map containing any headers which should be added to the outgoing * response. This methos creates the map if none exists, so it will never * return null * * @since 2.0 (note that this method existed in previous versions of HAPI but the method * signature has been changed from Map<String, String[]> to Map<String, List<String>> */ public Map> getResponseHeaders() { if (myResponseHeaders == null) { myResponseHeaders = new HashMap<>(); } return myResponseHeaders; } /** * In a RESTful client, this method will be populated with the HTTP status code that was returned with the HTTP response. *

* In a restful server, this method is currently ignored. *

*/ public String getResponseMimeType() { return myResponseMimeType; } /** * This method is currently only called internally by HAPI, it should not be called by user code. */ public void setResponseMimeType(String theResponseMimeType) { myResponseMimeType = theResponseMimeType; } /** * Returns the HTTP status code corresponding to this problem */ public int getStatusCode() { return myStatusCode; } /** * Does the exception have any headers which should be added to the outgoing response? * * @see #getResponseHeaders() * @since 2.0 */ public boolean hasResponseHeaders() { return myResponseHeaders != null && myResponseHeaders.isEmpty() == false; } /** * For unit tests only */ static boolean isExceptionTypeRegistered(Class theType) { return ourStatusCodeToExceptionType.values().contains(theType); } public static BaseServerResponseException newInstance(int theStatusCode, String theMessage) { if (ourStatusCodeToExceptionType.containsKey(theStatusCode)) { try { return ourStatusCodeToExceptionType .get(theStatusCode) .getConstructor(new Class[] {String.class}) .newInstance(theMessage); } catch (InstantiationException e) { throw new InternalErrorException(Msg.code(1912) + e); } catch (IllegalAccessException e) { throw new InternalErrorException(Msg.code(1913) + e); } catch (IllegalArgumentException e) { throw new InternalErrorException(Msg.code(1914) + e); } catch (InvocationTargetException e) { throw new InternalErrorException(Msg.code(1915) + e); } catch (NoSuchMethodException e) { throw new InternalErrorException(Msg.code(1916) + e); } catch (SecurityException e) { throw new InternalErrorException(Msg.code(1917) + e); } } return new UnclassifiedServerFailureException(theStatusCode, theMessage); } static void registerExceptionType(int theStatusCode, Class theType) { if (ourStatusCodeToExceptionType.containsKey(theStatusCode)) { throw new Error(Msg.code(1918) + "Can not register " + theType + " to status code " + theStatusCode + " because " + ourStatusCodeToExceptionType.get(theStatusCode) + " already registers that code"); } ourStatusCodeToExceptionType.put(theStatusCode, theType); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy