You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by gr...@apache.org on 2020/09/21 11:32:47 UTC
[ofbiz-plugins] branch trunk updated: Improved: Error handling for
the response and added new error 422 (Unprocessable Entity) to handle
validation errors(OFBIZ-11995)
This is an automated email from the ASF dual-hosted git repository.
grv pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-plugins.git
The following commit(s) were added to refs/heads/trunk by this push:
new 43d4c0b Improved: Error handling for the response and added new error 422 (Unprocessable Entity) to handle validation errors(OFBIZ-11995)
43d4c0b is described below
commit 43d4c0bd9899b1a22a453cf06a91c3d934cde3c2
Author: Girish Vasmatkar <gi...@hotwaxsystems.com>
AuthorDate: Mon Sep 21 17:02:24 2020 +0530
Improved: Error handling for the response and added new error 422 (Unprocessable Entity) to handle validation errors(OFBIZ-11995)
---
ofbiz-rest-impl/config/ApiUiLabels.xml | 15 ++++
.../ofbiz/ws/rs/process/ServiceRequestHandler.java | 93 +++++++++++++++++++--
.../org/apache/ofbiz/ws/rs/response/Error.java | 96 ++++++++++++++++++++++
.../ws/rs/response/{Error.java => Response.java} | 55 +++++--------
4 files changed, 221 insertions(+), 38 deletions(-)
diff --git a/ofbiz-rest-impl/config/ApiUiLabels.xml b/ofbiz-rest-impl/config/ApiUiLabels.xml
index 2071e6e..88795e0 100644
--- a/ofbiz-rest-impl/config/ApiUiLabels.xml
+++ b/ofbiz-rest-impl/config/ApiUiLabels.xml
@@ -40,4 +40,19 @@ under the License.
<value xml:lang="zh">不允许你浏览这个页面。</value>
<value xml:lang="zh-TW">不允許您檢視這個頁面.</value>
</property>
+ <property key="GenericServiceValidationErrorMessage">
+ <value xml:lang="en">${service} validation failed. The request contained invalid information and could not be processed.</value>
+ </property>
+ <property key="GenericServiceExecutionGenericEntityOperationErrorMessage">
+ <value xml:lang="en">${service} execution failed. The request contained invalid information and could not be processed.</value>
+ </property>
+ <property key="GenericServiceExecutionGenericExceptionErrorMessage">
+ <value xml:lang="en">${service} execution failed. The service encountered an error; please try again later.</value>
+ </property>
+ <property key="NoSuchEntityDefaultMessage">
+ <value xml:lang="en">${service} execution failed. The requested entity does not exist.</value>
+ </property>
+ <property key="GenericServiceErrorMessage">
+ <value xml:lang="en">${service} returned error. The request contained invalid information and could not be processed.</value>
+ </property>
</resource>
diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/process/ServiceRequestHandler.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/process/ServiceRequestHandler.java
index 51ce63b..b51e3fe 100644
--- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/process/ServiceRequestHandler.java
+++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/process/ServiceRequestHandler.java
@@ -19,15 +19,23 @@
package org.apache.ofbiz.ws.rs.process;
import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
-import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.ofbiz.base.util.UtilProperties;
import org.apache.ofbiz.base.util.UtilValidate;
+import org.apache.ofbiz.entity.GenericEntityException;
+import org.apache.ofbiz.entity.GenericEntityNotFoundException;
+import org.apache.ofbiz.entity.GenericNoSuchEntityException;
import org.apache.ofbiz.entity.GenericValue;
import org.apache.ofbiz.service.DispatchContext;
import org.apache.ofbiz.service.GenericServiceException;
@@ -35,10 +43,15 @@ import org.apache.ofbiz.service.LocalDispatcher;
import org.apache.ofbiz.service.ModelParam;
import org.apache.ofbiz.service.ModelService;
import org.apache.ofbiz.service.ServiceUtil;
+import org.apache.ofbiz.service.ServiceValidationException;
+import org.apache.ofbiz.ws.rs.core.ResponseStatus;
+import org.apache.ofbiz.ws.rs.response.Error;
import org.apache.ofbiz.ws.rs.util.RestApiUtil;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
public final class ServiceRequestHandler extends RestRequestHandler {
+ private static final String DEFAULT_MSG_UI_LABEL_RESOURCE = "ApiUiLabels";
private String service;
public ServiceRequestHandler(String service) {
@@ -68,7 +81,7 @@ public final class ServiceRequestHandler extends RestRequestHandler {
try {
result = dispatcher.runSync(service, serviceContext);
} catch (GenericServiceException e) {
- throw new InternalServerErrorException(e.getMessage());
+ return handleException(e);
}
Map<String, Object> responseData = new LinkedHashMap<>();
if (ServiceUtil.isSuccess(result)) {
@@ -84,9 +97,7 @@ public final class ServiceRequestHandler extends RestRequestHandler {
}
return RestApiUtil.success((String) result.get(ModelService.SUCCESS_MESSAGE), responseData);
} else {
- return RestApiUtil.error(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(),
- Response.Status.INTERNAL_SERVER_ERROR.getReasonPhrase(),
- (String) result.get(ModelService.ERROR_MESSAGE));
+ return errorFromServiceResult(service, result);
}
}
@@ -99,4 +110,76 @@ public final class ServiceRequestHandler extends RestRequestHandler {
}
return svc;
}
+
+ private Response handleException(GenericServiceException gse) {
+ Response.ResponseBuilder builder = null;
+ Throwable actualCause = gse.getCause();
+ if (actualCause == null) {
+ actualCause = gse;
+ } else if (actualCause instanceof InvokerInvocationException) {
+ actualCause = actualCause.getCause();
+ }
+
+ if (actualCause instanceof ServiceValidationException) {
+ ServiceValidationException validationException = (ServiceValidationException) actualCause;
+ Error error = new Error().type(actualCause.getClass().getSimpleName()).code(Response.Status.BAD_REQUEST.getStatusCode())
+ .description(Response.Status.BAD_REQUEST.getReasonPhrase())
+ .message(getErrorMessage(service, "GenericServiceValidationErrorMessage", getHttpRequest().getLocale()))
+ .errorDesc((validationException.getMessage())).additionalErrors(validationException.getMessageList());
+ builder = Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON).entity(error);
+ } else if (actualCause instanceof GenericNoSuchEntityException
+ || actualCause instanceof GenericEntityNotFoundException) {
+ Error error = new Error().type(actualCause.getClass().getSimpleName()).code(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode())
+ .description(Response.Status.INTERNAL_SERVER_ERROR.getReasonPhrase())
+ .message(getErrorMessage(service, "NoSuchEntityDefaultMessage", getHttpRequest().getLocale()))
+ .errorDesc(ExceptionUtils.getRootCauseMessage(gse));
+ builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR).type(MediaType.APPLICATION_JSON)
+ .entity(error);
+ } else if (actualCause instanceof GenericEntityException) {
+ Error error = new Error().type(actualCause.getClass().getSimpleName()).code(ResponseStatus.Custom.UNPROCESSABLE_ENTITY.getStatusCode())
+ .description(ResponseStatus.Custom.UNPROCESSABLE_ENTITY.getReasonPhrase())
+ .message(getErrorMessage(service, "GenericServiceExecutionGenericEntityOperationErrorMessage", getHttpRequest().getLocale()))
+ .errorDesc(ExceptionUtils.getRootCauseMessage(gse));
+ builder = Response.status(ResponseStatus.Custom.UNPROCESSABLE_ENTITY).type(MediaType.APPLICATION_JSON)
+ .entity(error);
+ } else {
+ Error error = new Error().type(actualCause.getClass().getSimpleName()).code(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode())
+ .description(Response.Status.INTERNAL_SERVER_ERROR.getReasonPhrase())
+ .message(getErrorMessage(service, "GenericServiceExecutionGenericExceptionErrorMessage", getHttpRequest().getLocale()))
+ .errorDesc(ExceptionUtils.getRootCauseMessage(gse));
+ builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR).type(MediaType.APPLICATION_JSON)
+ .entity(error);
+ }
+ return builder.build();
+ }
+
+ private String getErrorMessage(String serviceName, String errorKey, Locale locale) {
+ String error = UtilProperties.getMessage(DEFAULT_MSG_UI_LABEL_RESOURCE, errorKey, locale);
+ error = error.replace("${service}", serviceName);
+ return error;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Response errorFromServiceResult(String service, Map<String, Object> result) {
+ String errorMessage = null;
+ List<String> additionalErrorMessages = new LinkedList<>();
+ if (!UtilValidate.isEmpty(result.get(ModelService.ERROR_MESSAGE))) {
+ errorMessage = result.get(ModelService.ERROR_MESSAGE).toString();
+ }
+ if (!UtilValidate.isEmpty(result.get(ModelService.ERROR_MESSAGE_LIST))) {
+ List<String> errorMessageList = (List<String>) result.get(ModelService.ERROR_MESSAGE_LIST);
+ if (UtilValidate.isEmpty(errorMessage)) {
+ errorMessage = errorMessageList.get(0);
+ errorMessageList.remove(0);
+ }
+ for (int i = 0; i < errorMessageList.size(); i++) {
+ additionalErrorMessages.add(errorMessageList.get(i));
+ }
+ }
+ Error error = new Error().type("ServiceError").code(ResponseStatus.Custom.UNPROCESSABLE_ENTITY.getStatusCode())
+ .description(ResponseStatus.Custom.UNPROCESSABLE_ENTITY.getReasonPhrase())
+ .message(getErrorMessage(service, "GenericServiceErrorMessage", getHttpRequest().getLocale()))
+ .errorDesc(errorMessage);
+ return Response.status(ResponseStatus.Custom.UNPROCESSABLE_ENTITY).type(MediaType.APPLICATION_JSON).entity(error).build();
+ }
}
diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/response/Error.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/response/Error.java
index 24c7732..6f093d6 100644
--- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/response/Error.java
+++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/response/Error.java
@@ -20,16 +20,28 @@ package org.apache.ofbiz.ws.rs.response;
import java.util.List;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonRootName;
@JsonRootName(value = "error")
+@JsonPropertyOrder({ "statusCode", "statusDescription", "errorType", "errorMessage", "errorDescription",
+ "additionalErrors" })
public class Error {
private int statusCode;
private String statusDescription;
private String errorMessage;
+ @JsonProperty("errorType")
+ private String type;
+ @JsonProperty("errorDescription")
+ private String errorDesc;
private List<String> additionalErrors;
+ public Error() {
+
+ }
+
public Error(int statusCode, String statusDescription, String errorMessage) {
this.statusCode = statusCode;
this.statusDescription = statusDescription;
@@ -44,6 +56,69 @@ public class Error {
}
/**
+ * @param statusCode
+ * @return
+ */
+ public Error code(int statusCode) {
+ this.statusCode = statusCode;
+ return this;
+ }
+
+ /**
+ * @param statusDescription
+ * @return
+ */
+ public Error description(String statusDescription) {
+ this.statusDescription = statusDescription;
+ return this;
+ }
+
+ /**
+ * @param errorMessage
+ * @return
+ */
+ public Error message(String errorMessage) {
+ this.errorMessage = errorMessage;
+ return this;
+ }
+
+ /**
+ * @param type
+ * @return
+ */
+ public Error type(String type) {
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * @param statusCode
+ * @return
+ */
+ public Error statusCode(int statusCode) {
+ this.statusCode = statusCode;
+ return this;
+ }
+
+ /**
+ * @param additionalErrors
+ * @return
+ */
+ public Error additionalErrors(List<String> additionalErrors) {
+ this.additionalErrors = additionalErrors;
+ return this;
+ }
+
+ /**
+ * @param errorDesc
+ * @return
+ */
+ public Error errorDesc(String errorDesc) {
+ this.setErrorDesc(errorDesc);
+ return this;
+ }
+
+ /**
* @return the statusCode
*/
public int getStatusCode() {
@@ -51,6 +126,13 @@ public class Error {
}
/**
+ * @return the type
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
* @param statusCode the statusCode to set
*/
public void setStatusCode(int statusCode) {
@@ -99,4 +181,18 @@ public class Error {
this.additionalErrors = additionalErrors;
}
+ /**
+ * @return the errorDesc
+ */
+ public String getErrorDesc() {
+ return errorDesc;
+ }
+
+ /**
+ * @param errorDesc the errorDesc to set
+ */
+ public void setErrorDesc(String errorDesc) {
+ this.errorDesc = errorDesc;
+ }
+
}
diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/response/Error.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/response/Response.java
similarity index 58%
copy from ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/response/Error.java
copy to ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/response/Response.java
index 24c7732..f513eca 100644
--- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/response/Error.java
+++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/response/Response.java
@@ -18,30 +18,19 @@
*******************************************************************************/
package org.apache.ofbiz.ws.rs.response;
-import java.util.List;
-
-import com.fasterxml.jackson.annotation.JsonRootName;
-
-@JsonRootName(value = "error")
-public class Error {
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+@JsonPropertyOrder({ "statusCode", "statusDescription", "data", "error" })
+@JsonInclude(Include.NON_NULL)
+public class Response {
private int statusCode;
private String statusDescription;
- private String errorMessage;
- private List<String> additionalErrors;
-
- public Error(int statusCode, String statusDescription, String errorMessage) {
- this.statusCode = statusCode;
- this.statusDescription = statusDescription;
- this.errorMessage = errorMessage;
- }
-
- public Error(int statusCode, String statusDescription, String errorMessage, List<String> additionalErrors) {
- this.statusCode = statusCode;
- this.statusDescription = statusDescription;
- this.errorMessage = errorMessage;
- this.additionalErrors = additionalErrors;
- }
+ @JsonProperty("payload")
+ private Success success;
+ private Error error;
/**
* @return the statusCode
@@ -72,31 +61,31 @@ public class Error {
}
/**
- * @return the errorMessage
+ * @return the success
*/
- public String getErrorMessage() {
- return errorMessage;
+ public Success getSuccess() {
+ return success;
}
/**
- * @param errorMessage the errorMessage to set
+ * @param success the success to set
*/
- public void setErrorMessage(String errorMessage) {
- this.errorMessage = errorMessage;
+ public void setSuccess(Success success) {
+ this.success = success;
}
/**
- * @return the additionalErrors
+ * @return the error
*/
- public List<String> getAdditionalErrors() {
- return additionalErrors;
+ public Error getError() {
+ return error;
}
/**
- * @param additionalErrors the additionalErrors to set
+ * @param error the error to set
*/
- public void setAdditionalErrors(List<String> additionalErrors) {
- this.additionalErrors = additionalErrors;
+ public void setError(Error error) {
+ this.error = error;
}
}