aboutsummaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorDan Timoney <dtimoney@att.com>2020-06-26 15:56:48 -0400
committerDan Timoney <dtimoney@att.com>2020-06-29 09:01:18 -0400
commit385874a6fd067cb17323a27ecd1af62b4176aecc (patch)
treeb6f02d6dca3f496aacff8ae29b1c0cca71b7b866 /services
parentf3430368211a5eb435a56a70006831255dcdba2e (diff)
Add RFC 8040 compliant error handler
Add a new error handler that formats error responses consistent with RFC 8040 (RESTCONF) standards. Change-Id: I67a6ab626d943115570f2e74d0a8132933726bc8 Issue-ID: CCSDK-2482 Signed-off-by: Dan Timoney <dtimoney@att.com>
Diffstat (limited to 'services')
-rw-r--r--services/pom.xml15
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestApplicationError.java31
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestApplicationException.java14
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestError.java57
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestErrors.java28
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestException.java14
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestExceptionHandler.java131
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestProtocolError.java30
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestProtocolException.java14
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestRpcError.java31
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestRpcException.java14
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestTransportError.java30
-rw-r--r--services/src/main/java/org/onap/ccsdk/apps/services/RestTransportException.java14
-rw-r--r--services/src/test/java/org/onap/ccsdk/apps/services/RestExceptionHandlerTest.java362
-rw-r--r--services/src/test/resources/log4j2-test.xml14
15 files changed, 799 insertions, 0 deletions
diff --git a/services/pom.xml b/services/pom.xml
index d7e60f83..004e55e0 100644
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -39,6 +39,12 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-logging</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -97,6 +103,10 @@
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.onap.ccsdk.sli.core</groupId>
<artifactId>sliPluginUtils-provider</artifactId>
<version>${ccsdk.sli.core.version}</version>
@@ -116,6 +126,11 @@
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestApplicationError.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestApplicationError.java
new file mode 100644
index 00000000..e63e1d91
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestApplicationError.java
@@ -0,0 +1,31 @@
+package org.onap.ccsdk.apps.services;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+
+@JsonRootName(value="error")
+public class RestApplicationError extends RestError {
+
+
+ public RestApplicationError() {
+ this.errorType = "application";
+ }
+
+ public RestApplicationError(String errorTag, String errorMessage) {
+ this.errorType = "application";
+ this.errorTag = errorTag;
+ this.errorMessage = errorMessage;
+ this.errorInfo = errorMessage;
+ }
+
+ public RestApplicationError(String errorTag, String errorMessage, Throwable t) {
+ this.errorType = "application";
+ this.errorTag = errorTag;
+ this.errorMessage = errorMessage;
+ this.errorInfo = t.getLocalizedMessage();
+ }
+
+
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestApplicationException.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestApplicationException.java
new file mode 100644
index 00000000..73613399
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestApplicationException.java
@@ -0,0 +1,14 @@
+package org.onap.ccsdk.apps.services;
+
+public class RestApplicationException extends RestException {
+
+ public RestApplicationException(String errorTag, String errorMessage, int status) {
+ this.restError = new RestApplicationError(errorTag, errorMessage);
+ this.status = status;
+ }
+
+ public RestApplicationException(String errorTag, String errorMessage, Throwable t, int status) {
+ this.restError = new RestApplicationError(errorTag, errorMessage, t);
+ this.status = status;
+ }
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestError.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestError.java
new file mode 100644
index 00000000..d2e4c7ab
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestError.java
@@ -0,0 +1,57 @@
+package org.onap.ccsdk.apps.services;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+
+@JsonRootName(value="error")
+public abstract class RestError {
+
+ protected String errorType;
+ protected String errorTag;
+ protected String errorPath;
+ protected String errorMessage;
+ protected String errorInfo;
+
+
+ @JsonProperty("error-type")
+ public String getErrorType() {
+ return errorType;
+ }
+
+ @JsonProperty("error-tag")
+ public String getErrorTag() {
+ return errorTag;
+ }
+
+ public void setErrorTag(String errorTag) {
+ this.errorTag = errorTag;
+ }
+
+ @JsonProperty("error-path")
+ public String getErrorPath() {
+ return errorPath;
+ }
+
+ public void setErrorPath(String errorPath) {
+ this.errorPath = errorPath;
+ }
+
+ @JsonProperty("error-message")
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ @JsonProperty("error-info")
+ public String getErrorInfo() {
+ return errorInfo;
+ }
+
+ public void setErrorInfo(String errorInfo) {
+ this.errorInfo = errorInfo;
+ }
+
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestErrors.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestErrors.java
new file mode 100644
index 00000000..5fac3618
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestErrors.java
@@ -0,0 +1,28 @@
+package org.onap.ccsdk.apps.services;
+
+import com.fasterxml.jackson.annotation.JsonRootName;
+
+import java.util.LinkedList;
+import java.util.List;
+
+@JsonRootName(value="errors")
+public class RestErrors {
+ List<RestError> errors;
+
+ public RestErrors()
+ {
+ this.errors = new LinkedList<RestError>();
+ }
+
+ public RestErrors(RestError error) {
+ this.errors = new LinkedList<RestError>();
+ errors.add(error);
+ }
+ public void addError(RestError error) {
+ errors.add(error);
+ }
+
+ public List<RestError> getErrors() {
+ return errors;
+ }
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestException.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestException.java
new file mode 100644
index 00000000..52eab71b
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestException.java
@@ -0,0 +1,14 @@
+package org.onap.ccsdk.apps.services;
+
+abstract public class RestException extends Exception {
+ protected RestError restError;
+ protected int status;
+
+ public int getStatus() {
+ return status;
+ }
+
+ public RestError getRestError() {
+ return restError;
+ }
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestExceptionHandler.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestExceptionHandler.java
new file mode 100644
index 00000000..c517f402
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestExceptionHandler.java
@@ -0,0 +1,131 @@
+package org.onap.ccsdk.apps.services;
+
+import org.jvnet.hk2.annotations.Service;
+import org.springframework.beans.ConversionNotSupportedException;
+import org.springframework.beans.TypeMismatchException;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.validation.BindException;
+import org.springframework.web.HttpMediaTypeNotAcceptableException;
+import org.springframework.web.HttpMediaTypeNotSupportedException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingPathVariableException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.ServletRequestBindingException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
+import org.springframework.web.multipart.support.MissingServletRequestPartException;
+import org.springframework.web.servlet.NoHandlerFoundException;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+import javax.servlet.http.HttpServletRequest;
+
+@Order(Ordered.HIGHEST_PRECEDENCE)
+@RestControllerAdvice
+public class RestExceptionHandler extends ResponseEntityExceptionHandler {
+
+ @Override
+ protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestProtocolError("bad-method", "Method not supported", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestProtocolError("bad-media-type", "Media type not supported", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestProtocolError("bad-media-type", "Media type not acceptable", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleMissingPathVariable(MissingPathVariableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestApplicationError("missing-path", "Missing path variable", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestProtocolError("missing-param", "Missing servlet request parameter", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleServletRequestBindingException(ServletRequestBindingException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestApplicationError("request-binding", "Servlet binding exception", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleConversionNotSupported(ConversionNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestApplicationError("conversion", "Conversion not supported", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleTypeMismatch(TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestProtocolError("type-mismatch", "Type mismatch", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestProtocolError("bad-message", "HTTP message not readable", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleHttpMessageNotWritable(HttpMessageNotWritableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestProtocolError("bad-message", "HTTP message not writable", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestProtocolError("bad-message", "Method argument not valid", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleMissingServletRequestPart(MissingServletRequestPartException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestProtocolError("bad-message", "Missing servlet request part", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestApplicationError("binding-error", "Missing servlet request part", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestApplicationError("binding-error", "No handler found", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleAsyncRequestTimeoutException(AsyncRequestTimeoutException ex, HttpHeaders headers, HttpStatus status, WebRequest webRequest) {
+ return createResponseEntity(new RestApplicationError("timeout", "Async request timeout", ex), status);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return createResponseEntity(new RestApplicationError("internal-error", "Internal error", ex), status);
+ }
+
+ @ExceptionHandler({RestException.class})
+ protected ResponseEntity<Object> handleRestException(RestException ex, HttpServletRequest request) {
+ RestError error = ex.getRestError();
+ if (request != null) {
+ error.setErrorPath(request.getServletPath());
+ }
+ return createResponseEntity(error,HttpStatus.valueOf(ex.getStatus()));
+ }
+
+ private ResponseEntity<Object> createResponseEntity(RestError restError, HttpStatus status) {
+
+ return new ResponseEntity<>(new RestErrors(restError), status);
+ }
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestProtocolError.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestProtocolError.java
new file mode 100644
index 00000000..2e927b6a
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestProtocolError.java
@@ -0,0 +1,30 @@
+package org.onap.ccsdk.apps.services;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+
+@JsonRootName(value="error")
+public class RestProtocolError extends RestError {
+
+
+ public RestProtocolError() {
+ this.errorType = "protocol";
+ }
+
+ public RestProtocolError(String errorTag, String errorMessage) {
+ this.errorType = "protocol";
+ this.errorTag = errorTag;
+ this.errorMessage = errorMessage;
+ this.errorInfo = errorMessage;
+ }
+
+ public RestProtocolError(String errorTag, String errorMessage, Throwable t) {
+ this.errorType = "protocol";
+ this.errorTag = errorTag;
+ this.errorMessage = errorMessage;
+ this.errorInfo = t.getLocalizedMessage();
+ }
+
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestProtocolException.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestProtocolException.java
new file mode 100644
index 00000000..3de356bc
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestProtocolException.java
@@ -0,0 +1,14 @@
+package org.onap.ccsdk.apps.services;
+
+public class RestProtocolException extends RestException {
+
+ public RestProtocolException(String errorTag, String errorMessage, int status) {
+ this.restError = new RestProtocolError(errorTag, errorMessage);
+ this.status = status;
+ }
+
+ public RestProtocolException(String errorTag, String errorMessage, Throwable t, int status) {
+ this.restError = new RestProtocolError(errorTag, errorMessage, t);
+ this.status = status;
+ }
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestRpcError.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestRpcError.java
new file mode 100644
index 00000000..63611d8d
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestRpcError.java
@@ -0,0 +1,31 @@
+package org.onap.ccsdk.apps.services;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+
+@JsonRootName(value="error")
+public class RestRpcError extends RestError {
+
+
+ public RestRpcError() {
+ this.errorType = "rpc";
+ }
+
+ public RestRpcError(String errorTag, String errorMessage) {
+ this.errorType = "rpc";
+ this.errorTag = errorTag;
+ this.errorMessage = errorMessage;
+ this.errorInfo = errorMessage;
+ }
+
+ public RestRpcError(String errorTag, String errorMessage, Throwable t) {
+ this.errorType = "rpc";
+ this.errorTag = errorTag;
+ this.errorMessage = errorMessage;
+ this.errorInfo = t.getLocalizedMessage();
+ }
+
+
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestRpcException.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestRpcException.java
new file mode 100644
index 00000000..d69f3eb4
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestRpcException.java
@@ -0,0 +1,14 @@
+package org.onap.ccsdk.apps.services;
+
+public class RestRpcException extends RestException {
+
+ public RestRpcException(String errorTag, String errorMessage, int status) {
+ this.restError = new RestRpcError(errorTag, errorMessage);
+ this.status = status;
+ }
+
+ public RestRpcException(String errorTag, String errorMessage, Throwable t, int status) {
+ this.restError = new RestRpcError(errorTag, errorMessage, t);
+ this.status = status;
+ }
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestTransportError.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestTransportError.java
new file mode 100644
index 00000000..1fd539a6
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestTransportError.java
@@ -0,0 +1,30 @@
+package org.onap.ccsdk.apps.services;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+
+@JsonRootName(value = "error")
+public class RestTransportError extends RestError {
+
+
+ public RestTransportError() {
+ this.errorType = "transport";
+ }
+
+ public RestTransportError(String errorTag, String errorMessage) {
+ this.errorType = "transport";
+ this.errorTag = errorTag;
+ this.errorMessage = errorMessage;
+ this.errorInfo = errorMessage;
+ }
+
+ public RestTransportError(String errorTag, String errorMessage, Throwable t) {
+ this.errorType = "transport";
+ this.errorTag = errorTag;
+ this.errorMessage = errorMessage;
+ this.errorInfo = t.getLocalizedMessage();
+ }
+
+}
diff --git a/services/src/main/java/org/onap/ccsdk/apps/services/RestTransportException.java b/services/src/main/java/org/onap/ccsdk/apps/services/RestTransportException.java
new file mode 100644
index 00000000..971ee9b7
--- /dev/null
+++ b/services/src/main/java/org/onap/ccsdk/apps/services/RestTransportException.java
@@ -0,0 +1,14 @@
+package org.onap.ccsdk.apps.services;
+
+public class RestTransportException extends RestException {
+
+ public RestTransportException(String errorTag, String errorMessage, int status) {
+ this.restError = new RestTransportError(errorTag, errorMessage);
+ this.status = status;
+ }
+
+ public RestTransportException(String errorTag, String errorMessage, Throwable t, int status) {
+ this.restError = new RestTransportError(errorTag, errorMessage, t);
+ this.status = status;
+ }
+}
diff --git a/services/src/test/java/org/onap/ccsdk/apps/services/RestExceptionHandlerTest.java b/services/src/test/java/org/onap/ccsdk/apps/services/RestExceptionHandlerTest.java
new file mode 100644
index 00000000..242a6015
--- /dev/null
+++ b/services/src/test/java/org/onap/ccsdk/apps/services/RestExceptionHandlerTest.java
@@ -0,0 +1,362 @@
+package org.onap.ccsdk.apps.services;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.ConversionNotSupportedException;
+import org.springframework.beans.TypeMismatchException;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.validation.BindException;
+import org.springframework.web.HttpMediaTypeNotAcceptableException;
+import org.springframework.web.HttpMediaTypeNotSupportedException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingPathVariableException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.ServletRequestBindingException;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
+import org.springframework.web.multipart.support.MissingServletRequestPartException;
+import org.springframework.web.servlet.NoHandlerFoundException;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+
+
+public class RestExceptionHandlerTest {
+ private static final Logger log = LoggerFactory.getLogger("RestExceptionHandler");
+ private class RestExceptionHandlerWrapper extends RestExceptionHandler {
+ @Override
+ public ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleHttpRequestMethodNotSupported(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleHttpMediaTypeNotSupported(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleHttpMediaTypeNotAcceptable(ex, headers, status, request);
+ }
+
+ @Override
+ protected ResponseEntity<Object> handleMissingPathVariable(MissingPathVariableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleMissingPathVariable(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleMissingServletRequestParameter(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleServletRequestBindingException(ServletRequestBindingException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleServletRequestBindingException(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleConversionNotSupported(ConversionNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleConversionNotSupported(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleTypeMismatch(TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleTypeMismatch(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleHttpMessageNotReadable(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleHttpMessageNotWritable(HttpMessageNotWritableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleHttpMessageNotWritable(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleMethodArgumentNotValid(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleMissingServletRequestPart(MissingServletRequestPartException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleMissingServletRequestPart(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleBindException(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleNoHandlerFoundException(ex, headers, status, request);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleAsyncRequestTimeoutException(AsyncRequestTimeoutException ex, HttpHeaders headers, HttpStatus status, WebRequest webRequest) {
+ return super.handleAsyncRequestTimeoutException(ex, headers, status, webRequest);
+ }
+
+ @Override
+ public ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
+ return super.handleExceptionInternal(ex, body, headers, status, request);
+ }
+ }
+
+ RestExceptionHandler handler;
+
+ @Before
+ public void setUp() {
+ handler = new RestExceptionHandlerWrapper();
+ }
+
+ @Test
+ public void handleHttpRequestMethodNotSupported() throws JsonProcessingException {
+ String[] supportedMethods = {"GET", "POST", "PUT", "DELETE"};
+
+
+ ResponseEntity<Object> respEntity = handler.handleHttpRequestMethodNotSupported(new HttpRequestMethodNotSupportedException("PATCH", supportedMethods),
+ null, HttpStatus.METHOD_NOT_ALLOWED, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+
+
+ }
+
+ @Test
+ public void handleHttpMediaTypeNotSupported() throws JsonProcessingException {
+ MediaType[] supportedMediaTypeArray = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML};
+
+ ResponseEntity<Object> respEntity = handler.handleHttpMediaTypeNotSupported(new HttpMediaTypeNotSupportedException(MediaType.MULTIPART_MIXED, Arrays.asList(supportedMediaTypeArray)),
+ null, HttpStatus.UNSUPPORTED_MEDIA_TYPE, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleHttpMediaTypeNotAcceptable() throws JsonProcessingException {
+ MediaType[] supportedMediaTypeArray = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML};
+
+ ResponseEntity<Object> respEntity = handler.handleHttpMediaTypeNotAcceptable(new HttpMediaTypeNotAcceptableException(Arrays.asList(supportedMediaTypeArray)),
+ null, HttpStatus.UNSUPPORTED_MEDIA_TYPE, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+
+ }
+
+ @Test
+ public void handleMissingPathVariable() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleMissingPathVariable(new MissingPathVariableException("test", new MethodParameter(RestApplicationError.class.getDeclaredConstructors()[0],-1)),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleMissingServletRequestParameter() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleMissingServletRequestParameter(new MissingServletRequestParameterException("test", "string"),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleServletRequestBindingException() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleServletRequestBindingException(new ServletRequestBindingException("servlet request binding error"),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleConversionNotSupported() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleConversionNotSupported(new ConversionNotSupportedException("hello", Integer.class, new NumberFormatException()),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleTypeMismatch() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleTypeMismatch(new TypeMismatchException("hello", Integer.class, new NumberFormatException()),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleHttpMessageNotReadable() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleHttpMessageNotReadable(new HttpMessageNotReadableException("Message not readable"),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleHttpMessageNotWritable() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleHttpMessageNotWritable(new HttpMessageNotWritableException("Message not writable"),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleMethodArgumentNotValid() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleMethodArgumentNotValid(new MethodArgumentNotValidException(new MethodParameter(RestApplicationError.class.getDeclaredConstructors()[0],-1),
+ new BindException("target", "objectName")),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleMissingServletRequestPart() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleMissingServletRequestPart(new MissingServletRequestPartException("test"),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleBindException() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleBindException(new BindException("target", "objectName"),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleNoHandlerFoundException() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleNoHandlerFoundException(new NoHandlerFoundException("GET", "restconf/bogus", null),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleAsyncRequestTimeoutException() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleAsyncRequestTimeoutException(new AsyncRequestTimeoutException(),
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleExceptionInternal() throws JsonProcessingException {
+ ResponseEntity<Object> respEntity = handler.handleExceptionInternal(new NullPointerException(), null,
+ null, HttpStatus.INTERNAL_SERVER_ERROR, null);
+
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+ @Test
+ public void handleRestException() throws JsonProcessingException {
+
+ ResponseEntity<Object> respEntity = handler.handleRestException(new RestApplicationException("no-data-found", "No data found", HttpStatus.NOT_FOUND.value()), null);
+ assertTrue(respEntity.hasBody());
+ assertTrue(respEntity.getBody() instanceof RestErrors);
+
+ RestErrors restErrors = (RestErrors) respEntity.getBody();
+ ObjectMapper objectMapper = new ObjectMapper();
+ log.info("response : {}", objectMapper.writeValueAsString(restErrors));
+ }
+
+} \ No newline at end of file
diff --git a/services/src/test/resources/log4j2-test.xml b/services/src/test/resources/log4j2-test.xml
new file mode 100644
index 00000000..1408cf2a
--- /dev/null
+++ b/services/src/test/resources/log4j2-test.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="INFO">
+ <Appenders>
+ <Console name="Console" target="SYSTEM_OUT">
+ <PatternLayout
+ pattern="[%p] %d{yyyy-MM-dd HH:mm:ss} %c{1}:%L - %m%n"/>
+ </Console>
+ </Appenders>
+ <Loggers>
+ <Root level="info">
+ <AppenderRef ref="Console"/>
+ </Root>
+ </Loggers>
+</Configuration> \ No newline at end of file