syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From giacom...@apache.org
Subject [1/2] syncope git commit: [SYNCOPE-654] JPA error messages and Syncope client exceptions are correctly displayed
Date Tue, 14 Apr 2015 16:00:40 GMT
Repository: syncope
Updated Branches:
  refs/heads/master f1179b530 -> d2cc18c35


[SYNCOPE-654] JPA error messages and Syncope client exceptions are correctly displayed


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/c040d9e4
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/c040d9e4
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/c040d9e4

Branch: refs/heads/master
Commit: c040d9e4e475ed6741aa6575bca0b94acfc5ae88
Parents: a685073
Author: giacomolm <giacomolm@hotmail.it>
Authored: Tue Apr 14 16:33:45 2015 +0200
Committer: giacomolm <giacomolm@hotmail.it>
Committed: Tue Apr 14 16:33:45 2015 +0200

----------------------------------------------------------------------
 .../client/rest/RestClientExceptionMapper.java  |  16 ++-
 .../client/rest/RestClientFactoryBean.java      |   2 +
 .../core/persistence/dao/impl/UserDAOImpl.java  |   2 +-
 .../rest/utils/RestServiceExceptionMapper.java  |  46 ++++++-
 .../src/main/resources/errorMessages.properties |  17 +++
 .../core/rest/ExceptionMapperTestITCase.java    | 119 +++++++++++++++++++
 .../resources/oracle/persistence.properties     |   2 +-
 .../resources/sqlserver/persistence.properties  |   2 +-
 8 files changed, 189 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/c040d9e4/client/src/main/java/org/apache/syncope/client/rest/RestClientExceptionMapper.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/syncope/client/rest/RestClientExceptionMapper.java
b/client/src/main/java/org/apache/syncope/client/rest/RestClientExceptionMapper.java
index 1a9d2ef..b78ad17 100644
--- a/client/src/main/java/org/apache/syncope/client/rest/RestClientExceptionMapper.java
+++ b/client/src/main/java/org/apache/syncope/client/rest/RestClientExceptionMapper.java
@@ -76,17 +76,18 @@ public class RestClientExceptionMapper implements ExceptionMapper<Exception>,
Re
     }
 
     private SyncopeClientCompositeException checkSyncopeClientCompositeException(final Response
response) {
-        List<Object> exTypesInHeaders = response.getHeaders().get(RESTHeaders.ERROR_CODE);
+        List<String> exTypesInHeaders = response.getStringHeaders().get(RESTHeaders.ERROR_CODE);
         if (exTypesInHeaders == null) {
             LOG.debug("No " + RESTHeaders.ERROR_CODE + " provided");
             return null;
         }
+        List<String> exInfos = response.getStringHeaders().get(RESTHeaders.ERROR_INFO);
 
         final SyncopeClientCompositeException compException = SyncopeClientException.buildComposite();
 
         final Set<String> handledExceptions = new HashSet<String>();
-        for (Object exceptionTypeValue : exTypesInHeaders) {
-            final String exTypeAsString = (String) exceptionTypeValue;
+        for (int i = 0; i < exTypesInHeaders.size(); i++) {
+            String exTypeAsString = exTypesInHeaders.get(i);
             ClientExceptionType exceptionType = null;
             try {
                 exceptionType = ClientExceptionType.fromHeaderValue(exTypeAsString);
@@ -98,13 +99,10 @@ public class RestClientExceptionMapper implements ExceptionMapper<Exception>,
Re
 
                 final SyncopeClientException clientException = SyncopeClientException.build(exceptionType);
 
-                if (response.getHeaders().get(RESTHeaders.ERROR_INFO) != null
-                        && !response.getHeaders().get(RESTHeaders.ERROR_INFO).isEmpty())
{
-
-                    for (Object value : response.getHeaders().get(RESTHeaders.ERROR_INFO))
{
-                        final String element = value.toString();
+                if (exInfos != null && !exInfos.isEmpty()) {
+                    for (String element : exInfos) {
                         if (element.startsWith(exceptionType.getHeaderValue())) {
-                            clientException.getElements().add(StringUtils.substringAfter(value.toString(),
":"));
+                            clientException.getElements().add(StringUtils.substringAfter(element,
":"));
                         }
                     }
                 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/c040d9e4/client/src/main/java/org/apache/syncope/client/rest/RestClientFactoryBean.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/syncope/client/rest/RestClientFactoryBean.java
b/client/src/main/java/org/apache/syncope/client/rest/RestClientFactoryBean.java
index c3fa42c..97bb732 100644
--- a/client/src/main/java/org/apache/syncope/client/rest/RestClientFactoryBean.java
+++ b/client/src/main/java/org/apache/syncope/client/rest/RestClientFactoryBean.java
@@ -62,6 +62,8 @@ public class RestClientFactoryBean extends JAXRSClientFactoryBean {
         setServiceClass(serviceClass);
         final T serviceInstance = create(serviceClass);
         WebClient.client(serviceInstance).type(mediaType).accept(mediaType);
+        WebClient.getConfig(WebClient.client(serviceInstance)).getRequestContext().
+                put("org.apache.cxf.http.header.split", true);
         return serviceInstance;
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/c040d9e4/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/UserDAOImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/UserDAOImpl.java
b/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/UserDAOImpl.java
index 2f7162f..3d9d630 100644
--- a/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/UserDAOImpl.java
+++ b/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/UserDAOImpl.java
@@ -111,7 +111,7 @@ public class UserDAOImpl extends AbstractSubjectDAOImpl implements UserDAO
{
     @Override
     public SyncopeUser findByToken(final String token) {
         TypedQuery<SyncopeUser> query = entityManager.createQuery("SELECT e FROM "
+ SyncopeUser.class.getSimpleName()
-                + " e WHERE e.token = :token", SyncopeUser.class);
+                + " e WHERE e.token LIKE :token", SyncopeUser.class);
         query.setParameter("token", token);
 
         SyncopeUser result = null;

http://git-wip-us.apache.org/repos/asf/syncope/blob/c040d9e4/core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java
b/core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java
index e8f0e67..92c2034 100644
--- a/core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java
+++ b/core/src/main/java/org/apache/syncope/core/rest/utils/RestServiceExceptionMapper.java
@@ -18,7 +18,9 @@
  */
 package org.apache.syncope.core.rest.utils;
 
+import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -33,6 +35,7 @@ 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.commons.lang3.exception.ExceptionUtils;
 import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
 import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 import org.apache.cxf.jaxrs.validation.ValidationExceptionMapper;
@@ -50,11 +53,17 @@ import org.apache.syncope.core.workflow.WorkflowException;
 import org.identityconnectors.framework.common.exceptions.ConfigurationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
 import org.springframework.dao.DataIntegrityViolationException;
 import org.springframework.orm.jpa.JpaSystemException;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.transaction.TransactionSystemException;
 
+@Configuration
+@PropertySource("classpath:errorMessages.properties")
 @Provider
 public class RestServiceExceptionMapper implements ExceptionMapper<Exception>, ResponseExceptionMapper<Exception>
{
 
@@ -64,6 +73,17 @@ public class RestServiceExceptionMapper implements ExceptionMapper<Exception>,
R
 
     private final ValidationExceptionMapper validationEM = new ValidationExceptionMapper();
 
+    @Autowired
+    private Environment env;
+
+    private static final Map<String, String> exceptionCodeMap;
+
+    static {
+        exceptionCodeMap = new HashMap<String, String>();
+        exceptionCodeMap.put("23000", "UniqueConstraintViolation");
+        exceptionCodeMap.put("23505", "UniqueConstraintViolation");
+    }
+
     @Override
     public Response toResponse(final Exception ex) {
         LOG.error("Exception thrown by REST method: " + ex.getMessage(), ex);
@@ -90,9 +110,11 @@ public class RestServiceExceptionMapper implements ExceptionMapper<Exception>,
R
         } 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));
+            builder = builder(Response.Status.CONFLICT, ClientExceptionType.EntityExists,
getJPAMessage(ex));
         } else if (ex instanceof DataIntegrityViolationException) {
-            builder = builder(Response.Status.CONFLICT, ClientExceptionType.DataIntegrityViolation,
getExMessage(ex));
+            builder = builder(Response.Status.CONFLICT, ClientExceptionType.DataIntegrityViolation,
getJPAMessage(ex));
+        } else if (ex instanceof JpaSystemException) {
+            builder = builder(Response.Status.CONFLICT, ClientExceptionType.DataIntegrityViolation,
getJPAMessage(ex));
         } else {
             builder = processNotFoundExceptions(ex);
             if (builder == null) {
@@ -169,7 +191,7 @@ public class RestServiceExceptionMapper implements ExceptionMapper<Exception>,
R
             error.setType(sce.getType());
 
             for (String element : sce.getElements()) {
-                builder.header(RESTHeaders.ERROR_INFO, ex.getType().getInfoHeaderValue(element));
+                builder.header(RESTHeaders.ERROR_INFO, sce.getType().getInfoHeaderValue(element));
                 error.getElements().add(element);
             }
 
@@ -202,8 +224,8 @@ public class RestServiceExceptionMapper implements ExceptionMapper<Exception>,
R
         if (iee != null) {
             ClientExceptionType exType =
                     iee.getEntityClassSimpleName().endsWith("Policy")
-                    ? ClientExceptionType.InvalidPolicy
-                    : ClientExceptionType.valueOf("Invalid" + iee.getEntityClassSimpleName());
+                            ? ClientExceptionType.InvalidPolicy
+                            : ClientExceptionType.valueOf("Invalid" + iee.getEntityClassSimpleName());
 
             ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
             builder.header(RESTHeaders.ERROR_CODE, exType.getHeaderValue());
@@ -273,4 +295,18 @@ public class RestServiceExceptionMapper implements ExceptionMapper<Exception>,
R
     private String getExMessage(final Throwable ex) {
         return (ex.getCause() == null) ? ex.getMessage() : ex.getCause().getMessage();
     }
+
+    private String getJPAMessage(final Throwable ex) {
+        Throwable throwable = ExceptionUtils.getRootCause(ex);
+        String message = null;
+        if (throwable instanceof SQLException) {
+            String SQLState = ((SQLException) throwable).getSQLState();
+            String messageKey = exceptionCodeMap.get(SQLState);
+            if (messageKey != null) {
+                message = env.getProperty("errMessage." + messageKey);
+            }
+        }
+
+        return message == null ? getExMessage(ex) : message;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/c040d9e4/core/src/main/resources/errorMessages.properties
----------------------------------------------------------------------
diff --git a/core/src/main/resources/errorMessages.properties b/core/src/main/resources/errorMessages.properties
new file mode 100644
index 0000000..4e942db
--- /dev/null
+++ b/core/src/main/resources/errorMessages.properties
@@ -0,0 +1,17 @@
+# 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.
+errMessage.UniqueConstraintViolation=A violation of the constraint imposed by a unique index
or a unique constraint occurred

http://git-wip-us.apache.org/repos/asf/syncope/blob/c040d9e4/core/src/test/java/org/apache/syncope/core/rest/ExceptionMapperTestITCase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/syncope/core/rest/ExceptionMapperTestITCase.java
b/core/src/test/java/org/apache/syncope/core/rest/ExceptionMapperTestITCase.java
new file mode 100644
index 0000000..db87d4d
--- /dev/null
+++ b/core/src/test/java/org/apache/syncope/core/rest/ExceptionMapperTestITCase.java
@@ -0,0 +1,119 @@
+/*
+ * 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.core.rest;
+
+import static org.apache.syncope.core.rest.AbstractTest.attributeTO;
+import static org.apache.syncope.core.rest.AbstractTest.getUUIDString;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import org.apache.commons.io.IOUtils;
+import org.apache.syncope.common.to.RoleTO;
+import org.apache.syncope.common.to.SchemaTO;
+import org.apache.syncope.common.to.UserTO;
+import org.apache.syncope.common.types.AttributableType;
+import org.apache.syncope.common.types.AttributeSchemaType;
+import org.apache.syncope.common.types.SchemaType;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.JVM)
+public class ExceptionMapperTestITCase extends AbstractTest {
+
+    private static final Properties props = new Properties();
+
+    @BeforeClass
+    public static void setUpErrorMessages() throws IOException {
+        InputStream propStream = null;
+        try {
+            propStream = ConnectorTestITCase.class.getResourceAsStream("/errorMessages.properties");
+            props.load(propStream);
+        } catch (Exception e) {
+            LOG.error("Could not load /errorMessages.properties", e);
+        } finally {
+            IOUtils.closeQuietly(propStream);
+        }
+    }
+
+    @Test
+    public void uniqueSchemaConstraint() {
+        // 1. create an user schema with unique constraint
+        SchemaTO schemaTO = new SchemaTO();
+        String schema_UID = getUUIDString();
+        schemaTO.setName("unique" + schema_UID);
+        schemaTO.setType(AttributeSchemaType.String);
+        schemaTO.setUniqueConstraint(true);
+        createSchema(AttributableType.USER, SchemaType.NORMAL, schemaTO);
+
+        // 2. create an user with mandatory attributes and unique
+        UserTO userTO_1 = new UserTO();
+        String userId_1 = getUUIDString() + "issue654_1@syncope.apache.org";
+        userTO_1.setUsername(userId_1);
+        userTO_1.setPassword("password");
+
+        userTO_1.getAttrs().add(attributeTO("userId", userId_1));
+        userTO_1.getAttrs().add(attributeTO("fullname", userId_1));
+        userTO_1.getAttrs().add(attributeTO("surname", userId_1));
+        userTO_1.getAttrs().add(attributeTO("unique" + schema_UID, "unique" + schema_UID));
+
+        createUser(userTO_1);
+
+        // 3. create an other user with mandatory attributes and unique with the same value
of userTO_1
+        UserTO userTO_2 = new UserTO();
+        String userId_2 = getUUIDString() + "issue654_2@syncope.apache.org";
+        userTO_2.setUsername(userId_2);
+        userTO_2.setPassword("password");
+
+        userTO_2.getAttrs().add(attributeTO("userId", userId_2));
+        userTO_2.getAttrs().add(attributeTO("fullname", userId_2));
+        userTO_2.getAttrs().add(attributeTO("surname", userId_2));
+        userTO_2.getAttrs().add(attributeTO("unique" + schema_UID, "unique" + schema_UID));
+
+        try {
+            createUser(userTO_2);
+        } catch (Exception e) {
+            String message = props.getProperty("errMessage.UniqueConstraintViolation");
+            Assert.assertEquals(e.getMessage(), "DataIntegrityViolation [" + message + "]");
+        }
+    }
+
+    @Test
+    public void sameRoleName() {
+        //Create the first role
+        RoleTO roleTO_1 = new RoleTO();
+        String role_UUID = getUUIDString();
+        roleTO_1.setName("child1" + role_UUID);
+        roleTO_1.setParent(1L);
+        createRole(roleTO_1);
+        //Create the second role, with the same parent and the same role of roleTO_1
+        RoleTO roleTO_2 = new RoleTO();
+        roleTO_2.setName("child1" + role_UUID);
+        roleTO_2.setParent(1L);
+        try {
+            createRole(roleTO_2);
+        } catch (Exception e) {
+            String message = props.getProperty("errMessage.UniqueConstraintViolation");
+            Assert.assertEquals(e.getMessage(), "DataIntegrityViolation [" + message + "]");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/c040d9e4/core/src/test/resources/oracle/persistence.properties
----------------------------------------------------------------------
diff --git a/core/src/test/resources/oracle/persistence.properties b/core/src/test/resources/oracle/persistence.properties
index e3f6af1..2ac376a 100644
--- a/core/src/test/resources/oracle/persistence.properties
+++ b/core/src/test/resources/oracle/persistence.properties
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 jpa.driverClassName=oracle.jdbc.OracleDriver
-jpa.url=jdbc:oracle:thin:@localhost:1521:xe
+jpa.url=jdbc:oracle:thin:@pioppo:1521:orcl
 jpa.username=syncope
 jpa.password=syncope
 jpa.dialect=org.apache.openjpa.jdbc.sql.OracleDictionary

http://git-wip-us.apache.org/repos/asf/syncope/blob/c040d9e4/core/src/test/resources/sqlserver/persistence.properties
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sqlserver/persistence.properties b/core/src/test/resources/sqlserver/persistence.properties
index 17b73f2..a940c2d 100644
--- a/core/src/test/resources/sqlserver/persistence.properties
+++ b/core/src/test/resources/sqlserver/persistence.properties
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 jpa.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
-jpa.url=jdbc:sqlserver://localhost:1433;database=syncope;selectMethod=cursor;sendStringParametersAsUnicode=false
+jpa.url=jdbc:sqlserver://acacia:1433;database=syncope;selectMethod=cursor;sendStringParametersAsUnicode=false
 jpa.username=syncope
 jpa.password=syncope
 jpa.dialect=org.apache.openjpa.jdbc.sql.SQLServerDictionary


Mime
View raw message