You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2013/12/20 13:52:49 UTC

svn commit: r1552631 - in /syncope/trunk: common/src/main/java/org/apache/syncope/common/reqres/ErrorTO.java core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java

Author: ilgrosso
Date: Fri Dec 20 12:52:49 2013
New Revision: 1552631

URL: http://svn.apache.org/r1552631
Log:
[SYNCOPE_464] Added ErrorTO that will display error details (as XML or JSON)

Added:
    syncope/trunk/common/src/main/java/org/apache/syncope/common/reqres/ErrorTO.java   (with props)
Modified:
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java

Added: syncope/trunk/common/src/main/java/org/apache/syncope/common/reqres/ErrorTO.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/reqres/ErrorTO.java?rev=1552631&view=auto
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/reqres/ErrorTO.java (added)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/reqres/ErrorTO.java Fri Dec 20 12:52:49 2013
@@ -0,0 +1,66 @@
+/*
+ * 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.syncope.common.reqres;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.AbstractBaseBean;
+import org.apache.syncope.common.types.ClientExceptionType;
+
+@XmlRootElement(name = "error")
+@XmlType
+public class ErrorTO extends AbstractBaseBean {
+
+    private static final long serialVersionUID = 2435764161719225927L;
+
+    private int status;
+
+    private ClientExceptionType type;
+
+    private final List<Object> elements = new ArrayList<Object>();
+
+    public int getStatus() {
+        return status;
+    }
+
+    public void setStatus(final int status) {
+        this.status = status;
+    }
+
+    public ClientExceptionType getType() {
+        return type;
+    }
+
+    public void setType(final ClientExceptionType type) {
+        this.type = type;
+    }
+
+    @XmlElementWrapper(name = "elements")
+    @XmlElement(name = "element")
+    @JsonProperty("elements")
+    public List<Object> getElements() {
+        return elements;
+    }
+
+}

Propchange: syncope/trunk/common/src/main/java/org/apache/syncope/common/reqres/ErrorTO.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/trunk/common/src/main/java/org/apache/syncope/common/reqres/ErrorTO.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/trunk/common/src/main/java/org/apache/syncope/common/reqres/ErrorTO.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java?rev=1552631&r1=1552630&r2=1552631&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java Fri Dec 20 12:52:49 2013
@@ -18,23 +18,28 @@
  */
 package org.apache.syncope.core.rest.utils;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import javax.persistence.EntityExistsException;
 import javax.persistence.PersistenceException;
 import javax.persistence.RollbackException;
 import javax.ws.rs.BadRequestException;
+import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.ResponseBuilder;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 import org.apache.syncope.common.types.EntityViolationType;
 import org.apache.syncope.common.types.ClientExceptionType;
 import org.apache.syncope.common.types.RESTHeaders;
 import org.apache.syncope.common.SyncopeClientCompositeException;
 import org.apache.syncope.common.SyncopeClientException;
+import org.apache.syncope.common.reqres.ErrorTO;
 import org.apache.syncope.core.persistence.dao.MissingConfKeyException;
 import org.apache.syncope.core.persistence.dao.NotFoundException;
 import org.apache.syncope.core.persistence.validation.attrvalue.ParsingValidationException;
@@ -60,56 +65,53 @@ public class RestServiceExceptionMapper 
     public Response toResponse(final Exception ex) {
         LOG.error("Exception thrown by REST method: " + ex.getMessage(), ex);
 
+        ResponseBuilder builder;
+
         if (ex instanceof SyncopeClientException) {
             SyncopeClientException sce = (SyncopeClientException) ex;
-            return (sce.isComposite()
+            builder = sce.isComposite()
                     ? getSyncopeClientCompositeExceptionResponse(sce.asComposite())
-                    : getSyncopeClientExceptionResponse(sce));
-        }
-
-        if (ex instanceof AccessDeniedException) {
-            return Response.status(Response.Status.UNAUTHORIZED).
-                    header(HttpHeaders.WWW_AUTHENTICATE, BASIC_REALM_UNAUTHORIZED).
-                    build();
-        }
-
-        if (ex instanceof UnauthorizedRoleException) {
-            return buildResponse(Response.status(Response.Status.UNAUTHORIZED),
-                    ClientExceptionType.UnauthorizedRole,
-                    getExMessage(ex));
-        }
-
-        if (ex instanceof EntityExistsException) {
-            return buildResponse(Response.status(Response.Status.CONFLICT),
-                    ClientExceptionType.EntityExists,
-                    getExMessage(ex));
-        }
-
-        if (ex instanceof DataIntegrityViolationException) {
-            return buildResponse(Response.status(Response.Status.CONFLICT),
-                    ClientExceptionType.DataIntegrityViolation,
-                    getExMessage(ex));
-        }
-
-        Response response = processNotFoundExceptions(ex);
-        if (response != null) {
-            return response;
-        }
-
-        response = processInvalidEntityExceptions(ex);
-        if (response != null) {
-            return response;
-        }
-
-        response = processBadRequestExceptions(ex);
-        if (response != null) {
-            return response;
+                    : getSyncopeClientExceptionResponse(sce);
+        } else if (ex instanceof WebApplicationException) {
+            Response response = ((WebApplicationException) ex).getResponse();
+
+            ErrorTO error = new ErrorTO();
+            error.setStatus(response.getStatus());
+            error.setType(ClientExceptionType.Unknown);
+            error.getElements().add(getExMessage(ex));
+
+            builder = JAXRSUtils.fromResponse(response).entity(error);
+        } else if (ex instanceof AccessDeniedException) {
+            builder = Response.status(Response.Status.UNAUTHORIZED).
+                    header(HttpHeaders.WWW_AUTHENTICATE, BASIC_REALM_UNAUTHORIZED);
+        } else if (ex instanceof UnauthorizedRoleException) {
+            builder = builder(Response.Status.UNAUTHORIZED, ClientExceptionType.UnauthorizedRole, getExMessage(ex));
+        } else if (ex instanceof EntityExistsException) {
+            builder = builder(Response.Status.CONFLICT, ClientExceptionType.EntityExists, getExMessage(ex));
+        } else if (ex instanceof DataIntegrityViolationException) {
+            builder = builder(Response.Status.CONFLICT, ClientExceptionType.DataIntegrityViolation, getExMessage(ex));
+        } else {
+            builder = processNotFoundExceptions(ex);
+            if (builder == null) {
+                builder = processInvalidEntityExceptions(ex);
+                if (builder == null) {
+                    builder = processBadRequestExceptions(ex);
+                }
+                // ...or just report as InternalServerError
+                if (builder == null) {
+                    builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR).
+                            header(ClientExceptionType.Unknown.getElementHeaderName(), getExMessage(ex));
+
+                    ErrorTO error = new ErrorTO();
+                    error.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
+                    error.setType(ClientExceptionType.Unknown);
+                    error.getElements().add(getExMessage(ex));
+                    builder.entity(error);
+                }
+            }
         }
 
-        // Rest is interpreted as InternalServerError
-        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).
-                header(ClientExceptionType.Unknown.getElementHeaderName(), getExMessage(ex)).
-                build();
+        return builder.build();
     }
 
     @Override
@@ -118,47 +120,60 @@ public class RestServiceExceptionMapper 
                 "Call of fromResponse() method is not expected in RestServiceExceptionMapper");
     }
 
-    private Response getSyncopeClientExceptionResponse(final SyncopeClientException ex) {
-        ResponseBuilder responseBuilder = Response.status(ex.getType().getResponseStatus());
-        responseBuilder.header(RESTHeaders.EXCEPTION_TYPE, ex.getType().getHeaderValue());
+    private ResponseBuilder getSyncopeClientExceptionResponse(final SyncopeClientException ex) {
+        ResponseBuilder builder = Response.status(ex.getType().getResponseStatus());
+        builder.header(RESTHeaders.EXCEPTION_TYPE, ex.getType().getHeaderValue());
+
+        ErrorTO error = new ErrorTO();
+        error.setStatus(ex.getType().getResponseStatus().getStatusCode());
+        error.setType(ex.getType());
 
         for (Object element : ex.getElements()) {
-            responseBuilder.header(ex.getType().getElementHeaderName(), element);
+            builder.header(ex.getType().getElementHeaderName(), element);
+            error.getElements().add(element);
         }
 
-        return responseBuilder.build();
+        return builder.entity(error);
     }
 
-    private Response getSyncopeClientCompositeExceptionResponse(final SyncopeClientCompositeException ex) {
+    private ResponseBuilder getSyncopeClientCompositeExceptionResponse(final SyncopeClientCompositeException ex) {
         if (ex.getExceptions().size() == 1) {
             return getSyncopeClientExceptionResponse(ex.getExceptions().iterator().next());
         }
 
-        ResponseBuilder responseBuilder = Response.status(Response.Status.BAD_REQUEST);
+        ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
+
+        List<ErrorTO> errors = new ArrayList<ErrorTO>();
         for (SyncopeClientException sce : ex.getExceptions()) {
-            responseBuilder.header(RESTHeaders.EXCEPTION_TYPE, sce.getType().getHeaderValue());
+            builder.header(RESTHeaders.EXCEPTION_TYPE, sce.getType().getHeaderValue());
+
+            ErrorTO error = new ErrorTO();
+            error.setStatus(sce.getType().getResponseStatus().getStatusCode());
+            error.setType(sce.getType());
 
             for (Object element : sce.getElements()) {
-                responseBuilder.header(sce.getType().getElementHeaderName(), element);
+                builder.header(sce.getType().getElementHeaderName(), element);
+                error.getElements().add(element);
             }
+
+            errors.add(error);
         }
-        return responseBuilder.build();
-    }
 
-    private Response processNotFoundExceptions(final Exception ex) {
-        ResponseBuilder responseBuilder = Response.status(Response.Status.NOT_FOUND);
+        return builder.entity(errors);
+    }
 
+    private ResponseBuilder processNotFoundExceptions(final Exception ex) {
         if (ex instanceof javax.ws.rs.NotFoundException || ex instanceof NotFoundException) {
-            return buildResponse(responseBuilder, ClientExceptionType.NotFound, getExMessage(ex));
+            return builder(Response.Status.NOT_FOUND, ClientExceptionType.NotFound, getExMessage(ex));
         } else if (ex instanceof MissingConfKeyException) {
-            return buildResponse(responseBuilder, ClientExceptionType.NotFound,
+            return builder(Response.Status.NOT_FOUND, ClientExceptionType.NotFound,
                     getMessage(ex, ((MissingConfKeyException) ex).getConfKey()));
         }
 
         return null;
     }
 
-    private Response processInvalidEntityExceptions(final Exception ex) {
+    private ResponseBuilder processInvalidEntityExceptions(final Exception ex) {
         InvalidEntityException iee = null;
 
         if (ex instanceof InvalidEntityException) {
@@ -171,58 +186,67 @@ public class RestServiceExceptionMapper 
         }
 
         if (iee != null) {
-            ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
-
             ClientExceptionType exType = ClientExceptionType.valueOf("Invalid" + iee.getEntityClassSimpleName());
 
+            ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
             builder.header(RESTHeaders.EXCEPTION_TYPE, exType.getHeaderValue());
 
+            ErrorTO error = new ErrorTO();
+            error.setStatus(exType.getResponseStatus().getStatusCode());
+            error.setType(exType);
+
             for (Map.Entry<Class<?>, Set<EntityViolationType>> violation : iee.getViolations().entrySet()) {
                 for (EntityViolationType violationType : violation.getValue()) {
                     builder.header(exType.getElementHeaderName(),
                             violationType.name() + ": " + violationType.getMessage());
+                    error.getElements().add(violationType.name() + ": " + violationType.getMessage());
                 }
             }
 
-            return builder.build();
+            return builder;
         }
 
         return null;
     }
 
-    private Response processBadRequestExceptions(final Exception ex) {
-        ResponseBuilder responseBuilder = Response.status(Response.Status.BAD_REQUEST);
+    private ResponseBuilder processBadRequestExceptions(final Exception ex) {
+        ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
 
         if (ex instanceof BadRequestException) {
             if (((BadRequestException) ex).getResponse() == null) {
-                return responseBuilder.build();
+                return builder;
             } else {
-                return ((BadRequestException) ex).getResponse();
+                return JAXRSUtils.fromResponse(((BadRequestException) ex).getResponse());
             }
         } else if (ex instanceof WorkflowException) {
-            return buildResponse(responseBuilder, ClientExceptionType.Workflow, getExMessage(ex));
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.Workflow, getExMessage(ex));
         } else if (ex instanceof PersistenceException) {
-            return buildResponse(responseBuilder, ClientExceptionType.GenericPersistence, getExMessage(ex));
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.GenericPersistence, getExMessage(ex));
         } else if (ex instanceof org.apache.ibatis.exceptions.PersistenceException) {
-            return buildResponse(responseBuilder, ClientExceptionType.Workflow, getMessage(ex,
-                    "Currently unavailable. Please try later."));
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.Workflow,
+                    getMessage(ex, "Currently unavailable. Please try later."));
         } else if (ex instanceof JpaSystemException) {
-            return buildResponse(responseBuilder, ClientExceptionType.DataIntegrityViolation, getExMessage(ex));
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.DataIntegrityViolation, getExMessage(ex));
         } else if (ex instanceof ConfigurationException) {
-            return buildResponse(responseBuilder, ClientExceptionType.InvalidConnIdConf, getExMessage(ex));
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.InvalidConnIdConf, getExMessage(ex));
         } else if (ex instanceof ParsingValidationException) {
-            return buildResponse(responseBuilder, ClientExceptionType.InvalidValues, getExMessage(ex));
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.InvalidValues, getExMessage(ex));
         }
 
         return null;
     }
 
-    private Response buildResponse(final ResponseBuilder responseBuilder, final ClientExceptionType hType,
-            final String msg) {
+    private ResponseBuilder builder(final Response.Status status, final ClientExceptionType hType, final String msg) {
+        ResponseBuilder builder = Response.status(status).
+                header(RESTHeaders.EXCEPTION_TYPE, hType.getHeaderValue()).
+                header(hType.getElementHeaderName(), msg);
+
+        ErrorTO error = new ErrorTO();
+        error.setStatus(status.getStatusCode());
+        error.setType(hType);
+        error.getElements().add(msg);
 
-        return responseBuilder.header(RESTHeaders.EXCEPTION_TYPE, hType.getHeaderValue()).
-                header(hType.getElementHeaderName(), msg).
-                build();
+        return builder.entity(error);
     }
 
     private String getMessage(final Throwable ex, final String msg) {