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 2015/04/21 09:49:23 UTC

[08/40] syncope git commit: [SYNCOPE-654] Merge from 1_2_X; This closes #3

[SYNCOPE-654] Merge from 1_2_X; This closes #3


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

Branch: refs/heads/SYNCOPE-119
Commit: d2cc18c3518a534499c0b6737f096df251f976ab
Parents: f1179b5 c040d9e
Author: giacomolm <gi...@hotmail.it>
Authored: Tue Apr 14 17:53:27 2015 +0200
Committer: giacomolm <gi...@hotmail.it>
Committed: Tue Apr 14 17:53:27 2015 +0200

----------------------------------------------------------------------
 .../client/lib/RestClientExceptionMapper.java   |  16 ++-
 .../client/lib/RestClientFactoryBean.java       |   2 +
 core/rest-cxf/pom.xml                           |   6 +-
 .../rest/cxf/RestServiceExceptionMapper.java    |  49 ++++++--
 .../src/main/resources/errorMessages.properties |  17 +++
 fit/core-reference/pom.xml                      |   7 ++
 .../core/reference/ExceptionMapperITCase.java   | 117 +++++++++++++++++++
 7 files changed, 196 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/d2cc18c3/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java
----------------------------------------------------------------------
diff --cc client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java
index bb772bc,0000000..bcf7d03
mode 100644,000000..100644
--- a/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java
+++ b/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java
@@@ -1,126 -1,0 +1,124 @@@
 +/*
 + * 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.client.lib;
 +
 +import java.security.AccessControlException;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Set;
 +import javax.ws.rs.BadRequestException;
 +import javax.ws.rs.core.Response;
 +import javax.ws.rs.ext.ExceptionMapper;
 +import javax.ws.rs.ext.Provider;
 +import javax.xml.ws.WebServiceException;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
 +import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.types.ClientExceptionType;
 +import org.apache.syncope.common.rest.api.RESTHeaders;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +@Provider
 +public class RestClientExceptionMapper implements ExceptionMapper<Exception>, ResponseExceptionMapper<Exception> {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(RestClientExceptionMapper.class);
 +
 +    @Override
 +    public Response toResponse(final Exception exception) {
 +        throw new UnsupportedOperationException(
 +                "Call of toResponse() method is not expected in RestClientExceptionnMapper");
 +    }
 +
 +    @Override
 +    public Exception fromResponse(final Response response) {
 +        final int statusCode = response.getStatus();
 +        Exception ex;
 +
 +        // 1. Check for client (possibly composite) exception in HTTP header
 +        SyncopeClientCompositeException scce = checkSyncopeClientCompositeException(response);
 +        if (scce != null) {
 +            if (scce.getExceptions().size() == 1) {
 +                ex = scce.getExceptions().iterator().next();
 +            } else {
 +                ex = scce;
 +            }
 +        } // 2. Map SC_UNAUTHORIZED
 +        else if (statusCode == Response.Status.UNAUTHORIZED.getStatusCode()) {
 +            ex = new AccessControlException("Remote unauthorized exception");
 +        } // 3. Map SC_BAD_REQUEST
 +        else if (statusCode == Response.Status.BAD_REQUEST.getStatusCode()) {
 +            ex = new BadRequestException();
 +        } // 4. All other codes are mapped to runtime exception with HTTP code information
 +        else {
 +            ex = new WebServiceException(String.format("Remote exception with status code: %s",
 +                    Response.Status.fromStatusCode(statusCode).name()));
 +        }
 +        LOG.error("Exception thrown by REST methods: " + ex.getMessage(), ex);
 +        return ex;
 +    }
 +
 +    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);
 +            } catch (IllegalArgumentException e) {
 +                LOG.error("Unexpected value of " + RESTHeaders.ERROR_CODE + ": " + exTypeAsString, e);
 +            }
 +            if (exceptionType != null) {
 +                handledExceptions.add(exTypeAsString);
 +
 +                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, ":"));
 +                        }
 +                    }
 +                }
 +                compException.addException(clientException);
 +            }
 +        }
 +
 +        exTypesInHeaders.removeAll(handledExceptions);
 +        if (!exTypesInHeaders.isEmpty()) {
 +            LOG.error("Unmanaged exceptions: " + exTypesInHeaders);
 +        }
 +
 +        if (compException.hasExceptions()) {
 +            return compException;
 +        }
 +
 +        return null;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d2cc18c3/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java
----------------------------------------------------------------------
diff --cc client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java
index ca1c5d2,0000000..04b3892
mode 100644,000000..100644
--- a/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java
+++ b/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java
@@@ -1,67 -1,0 +1,69 @@@
 +/*
 + * 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.client.lib;
 +
 +import javax.ws.rs.core.MediaType;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
 +import org.apache.cxf.jaxrs.client.WebClient;
 +
 +/**
 + * Provides shortcuts for creating JAX-RS service instances via CXF's <tt>JAXRSClientFactoryBean</tt>.
 + */
 +public class RestClientFactoryBean extends JAXRSClientFactoryBean {
 +
 +    /**
 +     * Creates an anonymous instance of the given service class, for the given content type.
 +     *
 +     * @param <T> any service class
 +     * @param serviceClass service class reference
 +     * @param mediaType XML or JSON are supported
 +     * @return anonymous service instance of the given reference class
 +     */
 +    public <T> T createServiceInstance(final Class<T> serviceClass, final MediaType mediaType) {
 +        return createServiceInstance(serviceClass, mediaType, null, null);
 +    }
 +
 +    /**
 +     * Creates an authenticated instance of the given service class, for the given content type.
 +     *
 +     * @param <T> any service class
 +     * @param serviceClass service class reference
 +     * @param mediaType XML or JSON are supported
 +     * @param username username for REST authentication
 +     * @param password password for REST authentication
 +     * @return anonymous service instance of the given reference class
 +     */
 +    public <T> T createServiceInstance(
 +            final Class<T> serviceClass, final MediaType mediaType, final String username, final String password) {
 +
 +        if (StringUtils.isNotBlank(username)) {
 +            setUsername(username);
 +        }
 +        if (StringUtils.isNotBlank(password)) {
 +            setPassword(password);
 +        }
 +        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/d2cc18c3/core/rest-cxf/pom.xml
----------------------------------------------------------------------
diff --cc core/rest-cxf/pom.xml
index d9d06e0,0000000..66522eb
mode 100644,000000..100644
--- a/core/rest-cxf/pom.xml
+++ b/core/rest-cxf/pom.xml
@@@ -1,140 -1,0 +1,144 @@@
 +<?xml version="1.0" encoding="UTF-8"?>
 +<!--
 +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.
 +-->
 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 +
 +  <modelVersion>4.0.0</modelVersion>
 +
 +  <parent>
 +    <groupId>org.apache.syncope</groupId>
 +    <artifactId>syncope-core</artifactId>
 +    <version>2.0.0-SNAPSHOT</version>
 +  </parent>
 +
 +  <name>Apache Syncope Core REST CXF</name>
 +  <description>Apache Syncope Core REST CXF</description>
 +  <groupId>org.apache.syncope.core</groupId>
 +  <artifactId>syncope-core-rest-cxf</artifactId>
 +  <packaging>jar</packaging>
 +  
 +  <properties>
 +    <rootpom.basedir>${basedir}/../..</rootpom.basedir>
 +  </properties>
 +
 +  <dependencies>
 +    <dependency> 
 +      <groupId>javax.servlet</groupId> 
 +      <artifactId>javax.servlet-api</artifactId> 
 +      <scope>provided</scope>
 +    </dependency>
 +    
 +    <dependency>
 +      <groupId>org.apache.geronimo.specs</groupId>
 +      <artifactId>geronimo-jpa_2.0_spec</artifactId>
 +    </dependency>
-     
++
++    <dependency>
++      <groupId>org.springframework</groupId>
++      <artifactId>spring-context</artifactId>
++    </dependency>    
 +    <dependency>
 +      <groupId>org.springframework</groupId>
 +      <artifactId>spring-orm</artifactId>
 +    </dependency>      
 +    <dependency>
 +      <groupId>org.springframework</groupId>
 +      <artifactId>spring-web</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.springframework.security</groupId>
 +      <artifactId>spring-security-web</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.springframework.security</groupId>
 +      <artifactId>spring-security-config</artifactId>
 +    </dependency>
 +    
 +    <dependency>
 +      <groupId>com.fasterxml.jackson.jaxrs</groupId>
 +      <artifactId>jackson-jaxrs-json-provider</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>com.fasterxml.jackson.module</groupId>
 +      <artifactId>jackson-module-afterburner</artifactId>
 +    </dependency>
 +    
 +    <dependency>
 +      <groupId>org.apache.cxf</groupId>
 +      <artifactId>cxf-rt-frontend-jaxrs</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.cxf</groupId>
 +      <artifactId>cxf-rt-rs-extension-providers</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.cxf</groupId>
 +      <artifactId>cxf-rt-rs-extension-search</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.cxf</groupId>
 +      <artifactId>cxf-rt-frontend-jaxws</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.cxf</groupId>
 +      <artifactId>cxf-rt-rs-service-description</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.cxf</groupId>
 +      <artifactId>cxf-rt-rs-client</artifactId>
 +    </dependency>  
 +    
 +    <dependency>
 +      <groupId>org.apache.syncope.common</groupId>
 +      <artifactId>syncope-common-rest-api</artifactId>
 +      <version>${project.version}</version>
 +      <classifier>javadoc</classifier>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.syncope.core</groupId>
 +      <artifactId>syncope-core-logic</artifactId>
 +      <version>${project.version}</version>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.syncope.common</groupId>
 +      <artifactId>syncope-common-rest-api</artifactId>
 +      <version>${project.version}</version>
 +    </dependency>
 +  </dependencies>
 +
 +  <build>
 +    <plugins>
 +      <plugin>
 +        <groupId>org.apache.maven.plugins</groupId>
 +        <artifactId>maven-checkstyle-plugin</artifactId>
 +      </plugin>
 +      <plugin>
 +        <groupId>org.apache.maven.plugins</groupId>
 +        <artifactId>maven-pmd-plugin</artifactId>
 +      </plugin>
 +    </plugins>
 +    
 +    <resources>
 +      <resource>
 +        <directory>src/main/resources</directory>
 +        <filtering>true</filtering>
 +      </resource>
 +    </resources>
 +  </build>
 +</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/d2cc18c3/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/RestServiceExceptionMapper.java
----------------------------------------------------------------------
diff --cc core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/RestServiceExceptionMapper.java
index dbfb327,0000000..c10481f
mode 100644,000000..100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/RestServiceExceptionMapper.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/RestServiceExceptionMapper.java
@@@ -1,285 -1,0 +1,318 @@@
 +/*
 + * 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.cxf;
 +
++import java.sql.SQLException;
 +import java.util.ArrayList;
++import java.util.HashMap;
 +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.validation.ValidationException;
 +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.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;
 +import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.to.ErrorTO;
 +import org.apache.syncope.common.lib.types.ClientExceptionType;
 +import org.apache.syncope.common.lib.types.EntityViolationType;
 +import org.apache.syncope.common.rest.api.RESTHeaders;
 +import org.apache.syncope.core.misc.security.UnauthorizedRoleException;
 +import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
 +import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 +import org.apache.syncope.core.persistence.api.dao.DuplicateException;
 +import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 +import org.apache.syncope.core.workflow.api.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> {
 +
 +    private static final String BASIC_REALM_UNAUTHORIZED = "Basic realm=\"Apache Syncope authentication\"";
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(RestServiceExceptionMapper.class);
 +
 +    private final ValidationExceptionMapper validationEM = new ValidationExceptionMapper();
 +
++    @Autowired
++    private Environment env;
++
++    private static final Map<String, String> exceptionCodeMap;
++
++    static {
++        exceptionCodeMap = new HashMap<>();
++        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);
 +
 +        ResponseBuilder builder;
 +
 +        if (ex instanceof SyncopeClientException) {
 +            SyncopeClientException sce = (SyncopeClientException) ex;
 +            builder = sce.isComposite()
 +                    ? getSyncopeClientCompositeExceptionResponse(sce.asComposite())
 +                    : 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 || ex instanceof DuplicateException) {
-             builder = builder(Response.Status.CONFLICT, ClientExceptionType.EntityExists, getExMessage(ex));
-         } else if (ex instanceof DataIntegrityViolationException) {
-             builder = builder(Response.Status.CONFLICT, ClientExceptionType.DataIntegrityViolation, getExMessage(ex));
++            builder = builder(Response.Status.CONFLICT, ClientExceptionType.EntityExists, getJPAMessage(ex));
++        } else if (ex instanceof DataIntegrityViolationException || ex instanceof JpaSystemException) {
++            builder = builder(Response.Status.CONFLICT, ClientExceptionType.DataIntegrityViolation, getJPAMessage(ex));
 +        } else {
 +            builder = processNotFoundExceptions(ex);
 +            if (builder == null) {
 +                builder = processInvalidEntityExceptions(ex);
 +                if (builder == null) {
 +                    builder = processBadRequestExceptions(ex);
 +                }
 +                // process JAX-RS validation errors
 +                if (builder == null && ex instanceof ValidationException) {
 +                    builder = JAXRSUtils.fromResponse(validationEM.toResponse((ValidationException) ex)).
 +                            header(RESTHeaders.ERROR_CODE, ClientExceptionType.RESTValidation.getHeaderValue()).
 +                            header(RESTHeaders.ERROR_INFO,
 +                                    ClientExceptionType.RESTValidation.getInfoHeaderValue(getExMessage(ex)));
 +
 +                    ErrorTO error = new ErrorTO();
 +                    error.setStatus(ClientExceptionType.RESTValidation.getResponseStatus().getStatusCode());
 +                    error.setType(ClientExceptionType.RESTValidation);
 +                    error.getElements().add(getExMessage(ex));
 +                    builder.entity(error);
 +                }
 +                // ...or just report as InternalServerError
 +                if (builder == null) {
 +                    builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR).
 +                            header(RESTHeaders.ERROR_INFO,
 +                                    ClientExceptionType.Unknown.getInfoHeaderValue(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);
 +                }
 +            }
 +        }
 +
 +        return builder.build();
 +    }
 +
 +    @Override
 +    public Exception fromResponse(final Response r) {
 +        throw new UnsupportedOperationException(
 +                "Call of fromResponse() method is not expected in RestServiceExceptionMapper");
 +    }
 +
 +    private ResponseBuilder getSyncopeClientExceptionResponse(final SyncopeClientException ex) {
 +        ResponseBuilder builder = Response.status(ex.getType().getResponseStatus());
 +        builder.header(RESTHeaders.ERROR_CODE, ex.getType().getHeaderValue());
 +
 +        ErrorTO error = new ErrorTO();
 +        error.setStatus(ex.getType().getResponseStatus().getStatusCode());
 +        error.setType(ex.getType());
 +
 +        for (String element : ex.getElements()) {
 +            builder.header(RESTHeaders.ERROR_INFO, ex.getType().getInfoHeaderValue(element));
 +            error.getElements().add(element);
 +        }
 +
 +        return builder.entity(error);
 +    }
 +
 +    private ResponseBuilder getSyncopeClientCompositeExceptionResponse(final SyncopeClientCompositeException ex) {
 +        if (ex.getExceptions().size() == 1) {
 +            return getSyncopeClientExceptionResponse(ex.getExceptions().iterator().next());
 +        }
 +
 +        ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
 +
 +        List<ErrorTO> errors = new ArrayList<ErrorTO>();
 +        for (SyncopeClientException sce : ex.getExceptions()) {
 +            builder.header(RESTHeaders.ERROR_CODE, sce.getType().getHeaderValue());
 +
 +            ErrorTO error = new ErrorTO();
 +            error.setStatus(sce.getType().getResponseStatus().getStatusCode());
 +            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);
 +            }
 +
 +            errors.add(error);
 +        }
 +
 +        return builder.entity(errors);
 +    }
 +
 +    private ResponseBuilder processNotFoundExceptions(final Exception ex) {
 +        if (ex instanceof javax.ws.rs.NotFoundException || ex instanceof NotFoundException) {
 +            return builder(Response.Status.NOT_FOUND, ClientExceptionType.NotFound, getExMessage(ex));
 +        }
 +
 +        return null;
 +    }
 +
 +    private ResponseBuilder processInvalidEntityExceptions(final Exception ex) {
 +        InvalidEntityException iee = null;
 +
 +        if (ex instanceof InvalidEntityException) {
 +            iee = (InvalidEntityException) ex;
 +        }
 +        if (ex instanceof TransactionSystemException && ex.getCause() instanceof RollbackException
 +                && ex.getCause().getCause() instanceof InvalidEntityException) {
 +
 +            iee = (InvalidEntityException) ex.getCause().getCause();
 +        }
 +
 +        if (iee != null) {
-             ClientExceptionType exType =
-                     iee.getEntityClassSimpleName().endsWith("Policy")
-                             ? ClientExceptionType.InvalidPolicy
-                             : ClientExceptionType.valueOf("Invalid" + iee.getEntityClassSimpleName());
++            ClientExceptionType exType = iee.getEntityClassSimpleName().endsWith("Policy")
++                    ? ClientExceptionType.InvalidPolicy
++                    : ClientExceptionType.valueOf("Invalid" + iee.getEntityClassSimpleName());
 +
 +            ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
 +            builder.header(RESTHeaders.ERROR_CODE, 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(RESTHeaders.ERROR_INFO,
 +                            exType.getInfoHeaderValue(violationType.name() + ": " + violationType.getMessage()));
 +                    error.getElements().add(violationType.name() + ": " + violationType.getMessage());
 +                }
 +            }
 +
 +            return builder;
 +        }
 +
 +        return null;
 +    }
 +
 +    private ResponseBuilder processBadRequestExceptions(final Exception ex) {
 +        ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
 +
 +        // This exception might be raised by Activiti (if enabled)
 +        Class<?> ibatisPersistenceException = null;
 +        try {
 +            ibatisPersistenceException = Class.forName("org.apache.ibatis.exceptions.PersistenceException");
 +        } catch (ClassNotFoundException e) {
 +            // ignore
 +        }
 +
 +        if (ex instanceof BadRequestException) {
 +            if (((BadRequestException) ex).getResponse() == null) {
 +                return builder;
 +            } else {
 +                return JAXRSUtils.fromResponse(((BadRequestException) ex).getResponse());
 +            }
 +        } else if (ex instanceof WorkflowException) {
 +            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.Workflow, getExMessage(ex));
 +        } else if (ex instanceof PersistenceException) {
 +            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.GenericPersistence, getExMessage(ex));
 +        } else if (ibatisPersistenceException != null && ibatisPersistenceException.isAssignableFrom(ex.getClass())) {
 +            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.Workflow,
 +                    getMessage(ex, "Currently unavailable. Please try later."));
 +        } else if (ex instanceof JpaSystemException) {
 +            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.DataIntegrityViolation, getExMessage(ex));
 +        } else if (ex instanceof ConfigurationException) {
 +            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.InvalidConnIdConf, getExMessage(ex));
 +        } else if (ex instanceof ParsingValidationException) {
 +            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.InvalidValues, getExMessage(ex));
 +        }
 +
 +        return null;
 +    }
 +
 +    private ResponseBuilder builder(final Response.Status status, final ClientExceptionType hType, final String msg) {
 +        ResponseBuilder builder = Response.status(status).
 +                header(RESTHeaders.ERROR_CODE, hType.getHeaderValue()).
 +                header(RESTHeaders.ERROR_INFO, hType.getInfoHeaderValue(msg));
 +
 +        ErrorTO error = new ErrorTO();
 +        error.setStatus(status.getStatusCode());
 +        error.setType(hType);
 +        error.getElements().add(msg);
 +
 +        return builder.entity(error);
 +    }
 +
 +    private String getMessage(final Throwable ex, final String msg) {
 +        return (msg == null) ? getExMessage(ex) : msg;
 +    }
 +
 +    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/d2cc18c3/core/rest-cxf/src/main/resources/errorMessages.properties
----------------------------------------------------------------------
diff --cc core/rest-cxf/src/main/resources/errorMessages.properties
index 0000000,0000000..4e942db
new file mode 100644
--- /dev/null
+++ b/core/rest-cxf/src/main/resources/errorMessages.properties
@@@ -1,0 -1,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/d2cc18c3/fit/core-reference/pom.xml
----------------------------------------------------------------------
diff --cc fit/core-reference/pom.xml
index 93ee973,0000000..7f83b45
mode 100644,000000..100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@@ -1,863 -1,0 +1,870 @@@
 +<?xml version="1.0" encoding="UTF-8"?>
 +<!--
 +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.
 +-->
 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 +
 +  <modelVersion>4.0.0</modelVersion>
 +
 +  <parent>
 +    <groupId>org.apache.syncope</groupId>
 +    <artifactId>syncope-fit</artifactId>
 +    <version>2.0.0-SNAPSHOT</version>
 +  </parent>
 +
 +  <name>Apache Syncope FIT Core Reference</name>
 +  <description>Apache Syncope FIT Core Reference</description>
 +  <groupId>org.apache.syncope.fit</groupId>
 +  <artifactId>syncope-fit-core-reference</artifactId>
 +  <packaging>war</packaging>
 +  
 +  <properties>
 +    <jdbcdriver.groupId>com.h2database</jdbcdriver.groupId>
 +    <jdbcdriver.artifactId>h2</jdbcdriver.artifactId>
 +    
 +    <rootpom.basedir>${basedir}/../..</rootpom.basedir>
 +  </properties>
 +
 +  <dependencies>
 +    <dependency> 
 +      <groupId>javax.servlet</groupId> 
 +      <artifactId>javax.servlet-api</artifactId> 
 +    </dependency>
 +    <dependency>
 +      <groupId>javax.servlet.jsp</groupId>
 +      <artifactId>javax.servlet.jsp-api</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>javax.servlet</groupId>
 +      <artifactId>jstl</artifactId>
 +    </dependency>
 +    
 +    <dependency>
 +      <groupId>org.apache.syncope.core</groupId>
 +      <artifactId>syncope-core-rest-cxf</artifactId>
 +      <version>${project.version}</version>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.syncope.core</groupId>
 +      <artifactId>syncope-core-workflow-java</artifactId>
 +      <version>${project.version}</version>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.syncope.core</groupId>
 +      <artifactId>syncope-core-persistence-jpa</artifactId>
 +      <version>${project.version}</version>
 +    </dependency>
 +    
 +    <dependency>
 +      <groupId>org.slf4j</groupId>
 +      <artifactId>slf4j-api</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.logging.log4j</groupId>
 +      <artifactId>log4j-api</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.logging.log4j</groupId>
 +      <artifactId>log4j-core</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>com.lmax</groupId>
 +      <artifactId>disruptor</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.logging.log4j</groupId>
 +      <artifactId>log4j-slf4j-impl</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>commons-logging</groupId>
 +      <artifactId>commons-logging</artifactId>
 +      <scope>provided</scope>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.slf4j</groupId>
 +      <artifactId>jcl-over-slf4j</artifactId>
 +    </dependency>
 +    
 +    <dependency>
 +      <groupId>org.webjars</groupId>
 +      <artifactId>jquery</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.webjars</groupId>
 +      <artifactId>jquery-ui</artifactId>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.webjars</groupId>
 +      <artifactId>highlightjs</artifactId>
 +    </dependency>
 +    
 +    <!-- TEST -->
 +    <dependency>
 +      <groupId>org.apache.syncope.fit</groupId>
 +      <artifactId>syncope-fit-build-tools</artifactId>
 +      <version>${project.version}</version>
 +      <type>war</type>
 +      <scope>test</scope>
 +    </dependency>
 +    <dependency>
 +      <groupId>net.tirasa.connid.bundles.soap</groupId>
 +      <artifactId>wssample</artifactId>
 +      <type>war</type>
 +      <scope>test</scope>
 +    </dependency>
 +    <dependency>
 +      <groupId>com.h2database</groupId>
 +      <artifactId>h2</artifactId>
 +      <scope>test</scope>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.syncope.ext.camel</groupId>
 +      <artifactId>syncope-ext-camel-rest-cxf</artifactId>
 +      <version>${project.version}</version>
 +      <scope>test</scope>          
 +    </dependency>
 +    <dependency>
 +      <groupId>org.apache.syncope.client</groupId>
 +      <artifactId>syncope-client-lib</artifactId>
 +      <version>${project.version}</version>
 +      <scope>test</scope>
 +    </dependency>
 +    <dependency>
 +      <groupId>org.springframework</groupId>
 +      <artifactId>spring-test</artifactId>
 +      <scope>test</scope>
 +    </dependency>
 +    <dependency>
 +      <groupId>junit</groupId>
 +      <artifactId>junit</artifactId>
 +      <scope>test</scope>
 +    </dependency>
 +  </dependencies>
 +
 +  <build>
 +    <plugins>
 +      <plugin>
 +        <groupId>org.apache.maven.plugins</groupId>
 +        <artifactId>maven-war-plugin</artifactId>
 +        <inherited>true</inherited>
 +        <configuration>
 +          <failOnMissingWebXml>false</failOnMissingWebXml>
 +        </configuration>
 +      </plugin>
 +                
 +      <plugin>
 +        <groupId>org.apache.maven.plugins</groupId>
 +        <artifactId>maven-dependency-plugin</artifactId>
 +        <inherited>true</inherited>
 +        <executions>
 +          <execution>
 +            <id>set-bundles</id>
 +            <phase>process-test-resources</phase>
 +            <goals>
 +              <goal>copy</goal>
 +            </goals>
 +          </execution>
 +        </executions>
 +      </plugin>
 +      
 +      <plugin>
 +        <groupId>org.apache.maven.plugins</groupId>
 +        <artifactId>maven-antrun-plugin</artifactId>
 +        <inherited>true</inherited>
 +        <executions>
 +          <execution>
 +            <id>setupCSV</id>
 +            <phase>pre-integration-test</phase>
 +            <configuration>
 +              <target>
 +                <copy file="${project.build.directory}/test-classes/test.csv" todir="${test.csvdir.path}" overwrite="true"/>
 +              </target>
 +            </configuration>
 +            <goals>
 +              <goal>run</goal>
 +            </goals>
 +          </execution>
 +        </executions>
 +      </plugin>
 +
 +      <plugin>
 +        <groupId>org.apache.maven.plugins</groupId>
 +        <artifactId>maven-failsafe-plugin</artifactId>
 +        <inherited>true</inherited>
 +        <configuration>
 +          <systemPropertyVariables>
 +            <jaxrsContentType>${jaxrs.content.type}</jaxrsContentType>
 +          </systemPropertyVariables>
 +        </configuration>
 +        <executions>
 +          <execution>
 +            <id>verify</id>
 +            <goals>
 +              <goal>verify</goal>
 +            </goals>
 +          </execution>
 +        </executions>
 +      </plugin>
 +      
 +      <plugin>
 +        <groupId>org.codehaus.cargo</groupId>
 +        <artifactId>cargo-maven2-plugin</artifactId>
 +        <inherited>true</inherited>
 +        <configuration>
 +          <container>
 +            <dependencies>
 +              <dependency>
 +                <groupId>com.h2database</groupId>
 +                <artifactId>h2</artifactId>
 +              </dependency>
 +              <dependency>
 +                <groupId>${jdbcdriver.groupId}</groupId>
 +                <artifactId>${jdbcdriver.artifactId}</artifactId>
 +              </dependency>
 +            </dependencies>
 +          </container>
 +          <configuration>
 +            <type>standalone</type>
 +            <properties>
 +              <cargo.servlet.port>${cargo.servlet.port}</cargo.servlet.port>
 +              <cargo.tomcat.ajp.port>${cargo.tomcat.ajp.port}</cargo.tomcat.ajp.port>
 +              <cargo.rmi.port>${cargo.rmi.port}</cargo.rmi.port>
 +
 +              <cargo.jvmargs>-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=512m</cargo.jvmargs>
 +            </properties>
 +            <configfiles>
 +              <configfile>
 +                <file>${project.build.directory}/classes/context.xml</file>
 +                <todir>conf/</todir>
 +                <tofile>context.xml</tofile>
 +              </configfile>
 +            </configfiles>
 +          </configuration>
 +          <deployables>
 +            <deployable>
 +              <groupId>net.tirasa.connid.bundles.soap</groupId>
 +              <artifactId>wssample</artifactId>
 +              <type>war</type>
 +              <properties>
 +                <context>wssample</context>
 +              </properties>
 +            </deployable>
 +            <deployable>
 +              <groupId>org.apache.syncope.fit</groupId>
 +              <artifactId>syncope-fit-build-tools</artifactId>
 +              <type>war</type>
 +              <properties>
 +                <context>syncope-fit-build-tools</context>
 +              </properties>
 +            </deployable>
 +            <deployable>
 +              <location>${project.build.directory}/${project.build.finalName}</location>
 +              <pingURL>http://localhost:${cargo.servlet.port}/syncope/cacheStats.jsp</pingURL>
 +              <pingTimeout>60000</pingTimeout>
 +              <properties>
 +                <context>syncope</context>
 +              </properties>
 +            </deployable>
 +          </deployables>
 +        </configuration>
 +        <executions>
 +          <execution>
 +            <id>start-container</id>
 +            <phase>pre-integration-test</phase>
 +            <goals>
 +              <goal>start</goal>
 +            </goals>
 +          </execution>
 +          <execution>
 +            <id>stop-container</id>
 +            <phase>post-integration-test</phase>
 +            <goals>
 +              <goal>stop</goal>
 +            </goals>
 +          </execution>
 +        </executions>
 +      </plugin>
 +      
 +      <plugin>
 +        <groupId>org.apache.maven.plugins</groupId>
 +        <artifactId>maven-checkstyle-plugin</artifactId>
 +      </plugin>
 +      <plugin>
 +        <groupId>org.apache.maven.plugins</groupId>
 +        <artifactId>maven-pmd-plugin</artifactId>
 +      </plugin>      
 +                          
 +      <plugin>
 +        <groupId>org.codehaus.mojo</groupId>
 +        <artifactId>ianal-maven-plugin</artifactId>
 +        <configuration>
 +          <skip>true</skip>
 +        </configuration>
 +      </plugin>
 +    </plugins>
 +    
 +    <resources>
 +      <resource>
 +        <directory>src/main/resources</directory>
 +        <filtering>true</filtering>
 +      </resource>
 +      <resource>
 +        <directory>${basedir}/../../core/persistence-jpa/src/test/resources</directory>
 +        <includes>
 +          <include>content.xml</include>
 +          <include>persistence.properties</include>
 +        </includes>
 +        <filtering>true</filtering>
 +      </resource>
 +      <resource>
 +        <directory>${basedir}/../../core/misc/src/main/resources</directory>
 +        <includes>
 +          <include>security.properties</include>
 +        </includes>
 +        <filtering>true</filtering>
 +      </resource>
 +    </resources>
 +    <testResources>
 +      <testResource>
 +        <directory>src/test/resources</directory>
 +        <filtering>true</filtering>
 +      </testResource>
++      <testResource>
++        <directory>${basedir}/../../core/rest-cxf/src/main/resources</directory>
++        <includes>
++          <include>errorMessages.properties</include>
++        </includes>
++        <filtering>true</filtering>
++      </testResource>
 +    </testResources>
 +  </build>
 +  
 +  <profiles>
 +    <profile>
 +      <id>postgres-it</id>
 +
 +      <properties>
 +        <jdbcdriver.groupId>org.postgresql</jdbcdriver.groupId>
 +        <jdbcdriver.artifactId>postgresql</jdbcdriver.artifactId>
 +      </properties>
 +
 +      <dependencies>
 +        <dependency>
 +          <groupId>org.postgresql</groupId>
 +          <artifactId>postgresql</artifactId>
 +          <version>9.4-1200-jdbc41</version>
 +          <scope>test</scope>
 +        </dependency>
 +      </dependencies>
 +
 +      <build>
 +        <defaultGoal>clean verify</defaultGoal>
 +
 +        <resources>
 +          <resource>
 +            <directory>src/main/resources</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +          <resource>
 +            <directory>src/main/resources/postgres</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +        </resources>
 +      </build>
 +    </profile>
 +    
 +    <profile>
 +      <id>mysql-it</id>
 +
 +      <properties>
 +        <jdbcdriver.groupId>mysql</jdbcdriver.groupId>
 +        <jdbcdriver.artifactId>mysql-connector-java</jdbcdriver.artifactId>
 +      </properties>
 +
 +      <dependencies>
 +        <dependency>
 +          <groupId>mysql</groupId>
 +          <artifactId>mysql-connector-java</artifactId>
 +          <version>5.1.34</version>
 +          <scope>test</scope>
 +        </dependency>
 +      </dependencies>
 +      
 +      <build>
 +        <defaultGoal>clean verify</defaultGoal>
 +
 +        <resources>
 +          <resource>
 +            <directory>src/main/resources</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +          <resource>
 +            <directory>src/main/resources/mysql</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +        </resources>
 +      </build>
 +    </profile>
 +    
 +    <profile>
 +      <id>mariadb-it</id>
 +
 +      <properties>
 +        <jdbcdriver.groupId>org.mariadb.jdbc</jdbcdriver.groupId>
 +        <jdbcdriver.artifactId>mariadb-java-client</jdbcdriver.artifactId>
 +      </properties>
 +
 +      <dependencies>
 +        <dependency>
 +          <groupId>org.mariadb.jdbc</groupId>
 +          <artifactId>mariadb-java-client</artifactId>
 +          <version>1.1.8</version>
 +          <scope>test</scope>
 +        </dependency>
 +      </dependencies>
 +      
 +      <build>
 +        <defaultGoal>clean verify</defaultGoal>
 +
 +        <resources>
 +          <resource>
 +            <directory>src/main/resources</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +          <resource>
 +            <directory>src/main/resources/mariadb</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +        </resources>
 +      </build>
 +    </profile>
 +    
 +    <profile>
 +      <id>oracle-it</id>
 +
 +      <properties>
 +        <jdbcdriver.groupId>com.oracle</jdbcdriver.groupId>
 +        <jdbcdriver.artifactId>ojdbc6</jdbcdriver.artifactId>
 +      </properties>
 +
 +      <dependencies>
 +        <dependency>
 +          <groupId>com.oracle</groupId>
 +          <artifactId>ojdbc6</artifactId>
 +          <version>11.1.0</version>
 +          <scope>test</scope>
 +        </dependency>
 +      </dependencies>
 +      
 +      <build>
 +        <defaultGoal>clean verify</defaultGoal>
 +
 +        <resources>
 +          <resource>
 +            <directory>src/main/resources</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +          <resource>
 +            <directory>src/main/resources/oracle</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +        </resources>
 +      </build>
 +    </profile>
 +
 +    <profile>
 +      <id>sqlserver-it</id>
 +
 +      <properties>
 +        <jdbcdriver.groupId>com.microsoft.sqlserver</jdbcdriver.groupId>
 +        <jdbcdriver.artifactId>sqljdbc4</jdbcdriver.artifactId>
 +      </properties>
 +
 +      <dependencies>
 +        <dependency>
 +          <groupId>com.microsoft.sqlserver</groupId>
 +          <artifactId>sqljdbc4</artifactId>
 +          <version>4.0</version>
 +          <scope>test</scope>
 +        </dependency>
 +      </dependencies>
 +      
 +      <build>
 +        <defaultGoal>clean verify</defaultGoal>
 +
 +        <resources>
 +          <resource>
 +            <directory>src/main/resources</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +          <resource>
 +            <directory>src/main/resources/sqlserver</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +        </resources>
 +      </build>
 +    </profile>
 +    
 +    <profile>
 +      <id>glassfish-it</id>
 +
 +      <dependencies>
 +        <dependency>
 +          <groupId>com.h2database</groupId>
 +          <artifactId>h2</artifactId>
 +        </dependency>
 +      </dependencies>
 +
 +      <build>
 +        <defaultGoal>clean verify</defaultGoal>
 +
 +        <plugins>
 +          <plugin>
 +            <groupId>org.codehaus.cargo</groupId>
 +            <artifactId>cargo-maven2-plugin</artifactId>
 +            <inherited>true</inherited>
 +            <configuration>
 +              <container>
 +                <containerId>glassfish4x</containerId>
 +                <zipUrlInstaller>
 +                  <url>http://download.java.net/glassfish/4.1/release/glassfish-4.1.zip</url>
 +                  <downloadDir>${settings.localRepository}/org/codehaus/cargo/cargo-container-archives</downloadDir>
 +                  <extractDir>${project.build.directory}/cargo/extract</extractDir>
 +                </zipUrlInstaller>
 +                <log>${cargo.log}</log>
 +                <output>${cargo.output}</output>
 +              </container>
 +            </configuration>
 +          </plugin>
 +        </plugins>
 +      </build>
 +    </profile>
 +    
 +    <profile>
 +      <id>jboss-it</id>
 +
 +      <dependencies>
 +        <dependency>
 +          <groupId>com.h2database</groupId>
 +          <artifactId>h2</artifactId>
 +        </dependency>
 +        
 +        <dependency>
 +          <groupId>org.apache.syncope.ext.camel</groupId>
 +          <artifactId>syncope-ext-camel-persistence-jpa</artifactId>
 +          <version>${project.version}</version>
 +        </dependency>
 +      </dependencies>
 +
 +      <build>
 +        <defaultGoal>clean verify</defaultGoal>
 +
 +        <plugins>
 +          <plugin>
 +            <groupId>org.apache.maven.plugins</groupId>
 +            <artifactId>maven-war-plugin</artifactId>
 +            <configuration>
 +              <packagingExcludes>WEB-INF/lib/syncope-*-persistence-jpa-${project.version}.jar</packagingExcludes>
 +            </configuration>
 +          </plugin>
 +          <plugin>
 +            <groupId>org.apache.maven.plugins</groupId>
 +            <artifactId>maven-dependency-plugin</artifactId>
 +            <inherited>true</inherited>
 +            <executions>
 +              <execution>
 +                <id>unpack-jpa-entities</id>
 +                <phase>process-resources</phase>
 +                <goals>
 +                  <goal>unpack</goal>
 +                </goals>
 +                <configuration>
 +                  <artifactItems>
 +                    <artifactItem>
 +                      <groupId>org.apache.syncope.core</groupId>
 +                      <artifactId>syncope-core-persistence-jpa</artifactId>
 +                      <version>${project.version}</version>
 +                      <type>jar</type>
 +                      <overWrite>false</overWrite>
 +                    </artifactItem>
 +                    <artifactItem>
 +                      <groupId>org.apache.syncope.ext.camel</groupId>
 +                      <artifactId>syncope-ext-camel-persistence-jpa</artifactId>
 +                      <version>${project.version}</version>
 +                      <type>jar</type>
 +                      <overWrite>false</overWrite>
 +                    </artifactItem>
 +                  </artifactItems>
 +                  <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
 +                </configuration>
 +              </execution>
 +            </executions>
 +          </plugin>
 +          <plugin>
 +            <groupId>org.apache.maven.plugins</groupId>
 +            <artifactId>maven-antrun-plugin</artifactId>
 +            <inherited>true</inherited>
 +            <executions>
 +              <execution>
 +                <id>remove-jpa-jar</id>
 +                <phase>package</phase>
 +                <configuration>
 +                  <target>
 +                    <delete> 
 +                      <fileset dir="${project.build.directory}/${project.build.finalName}/WEB-INF/lib"
 +                               includes="syncope-*-persistence-jpa-${project.version}.jar"/>
 +                    </delete>
 +                  </target>
 +                </configuration>
 +                <goals>
 +                  <goal>run</goal>
 +                </goals>
 +              </execution>
 +            </executions>
 +          </plugin>
 +
 +          <plugin>
 +            <groupId>org.codehaus.cargo</groupId>
 +            <artifactId>cargo-maven2-plugin</artifactId>
 +            <inherited>true</inherited>
 +            <configuration>
 +              <container>
 +                <containerId>wildfly8x</containerId>
 +                <zipUrlInstaller>
 +                  <url>http://download.jboss.org/wildfly/8.2.0.Final/wildfly-8.2.0.Final.zip</url>
 +                  <downloadDir>${settings.localRepository}/org/codehaus/cargo/cargo-container-archives</downloadDir>
 +                  <extractDir>${project.build.directory}/cargo/extract</extractDir>
 +                </zipUrlInstaller>
 +                <log>${cargo.log}</log>
 +                <output>${cargo.output}</output>
 +              </container>
 +              <configuration>
 +                <properties>
 +                  <cargo.jvmargs>-Xms1024m -Xmx2048m -XX:PermSize=512m -XX:MaxPermSize=1024m -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled</cargo.jvmargs>
 +                </properties>
 +              </configuration>
 +            </configuration>            
 +          </plugin>
 +        </plugins>
 +
 +        <resources>
 +          <resource>
 +            <directory>src/main/resources</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +          <resource>
 +            <directory>src/main/resources/jboss</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +        </resources>
 +      </build>
 +    </profile>
 +
 +    <profile>
 +      <id>debug</id>
 +
 +      <properties>
 +        <skipTests>true</skipTests>
 +      </properties>
 +
 +      <build>
 +        <defaultGoal>clean verify cargo:run</defaultGoal>
 +
 +        <plugins>
 +          <plugin>
 +            <groupId>org.codehaus.cargo</groupId>
 +            <artifactId>cargo-maven2-plugin</artifactId>
 +            <inherited>true</inherited>
 +            <configuration>
 +              <configuration>
 +                <properties>
 +                  <cargo.jvmargs>-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n
 +                    -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=512m</cargo.jvmargs>
 +                </properties>
 +              </configuration>
 +            </configuration>
 +            <executions>
 +              <execution>
 +                <id>start-container</id>
 +                <phase>none</phase>
 +              </execution>
 +              <execution>
 +                <id>stop-container</id>
 +                <phase>none</phase>
 +              </execution>
 +            </executions>
 +          </plugin>
 +        </plugins>
 +      </build>
 +    </profile>
 +    
 +    <profile>
 +      <id>skipTests</id>
 +
 +      <dependencies>
 +        <dependency>
 +          <groupId>com.h2database</groupId>
 +          <artifactId>h2</artifactId>
 +        </dependency>
 +      </dependencies>
 +
 +      <build>
 +        <plugins>
 +          <plugin>
 +            <groupId>org.apache.maven.plugins</groupId>
 +            <artifactId>maven-failsafe-plugin</artifactId>
 +            <inherited>true</inherited>
 +            <configuration>
 +              <skipTests>${skipTests}</skipTests>
 +            </configuration>
 +          </plugin>
 +
 +          <plugin>
 +            <groupId>org.codehaus.cargo</groupId>
 +            <artifactId>cargo-maven2-plugin</artifactId>
 +            <inherited>true</inherited>
 +            <configuration>
 +              <deployables>
 +                <deployable>
 +                  <location>${project.build.directory}/${project.build.finalName}.war</location>
 +                </deployable>
 +              </deployables>
 +            </configuration>
 +            <executions>
 +              <execution>
 +                <id>install-container</id>
 +                <phase>package</phase>
 +                <goals>
 +                  <goal>install</goal>
 +                </goals>
 +              </execution>
 +              <execution>
 +                <id>start-container</id>
 +                <phase>none</phase>
 +              </execution>
 +              <execution>
 +                <id>stop-container</id>
 +                <phase>none</phase>
 +              </execution>
 +            </executions>
 +          </plugin>
 +        </plugins>
 +      </build>
 +    </profile>
 +    
 +    <profile>
 +      <id>all</id>
 +      <activation>
 +        <activeByDefault>true</activeByDefault>
 +      </activation>
 +      
 +      <dependencies>
 +        <dependency>
 +          <groupId>org.apache.syncope.core</groupId>
 +          <artifactId>syncope-core-workflow-activiti</artifactId>
 +          <version>${project.version}</version>
 +        </dependency>
 +
 +        <dependency>
 +          <groupId>org.apache.syncope.ext.camel</groupId>
 +          <artifactId>syncope-ext-camel-rest-cxf</artifactId>
 +          <version>${project.version}</version>
 +        </dependency>
 +        <dependency>
 +          <groupId>org.apache.syncope.ext.camel</groupId>
 +          <artifactId>syncope-ext-camel-persistence-jpa</artifactId>
 +          <version>${project.version}</version>
 +        </dependency>
 +        <dependency>
 +          <groupId>org.apache.syncope.ext.camel</groupId>
 +          <artifactId>syncope-ext-camel-provisioning</artifactId>
 +          <version>${project.version}</version>
 +        </dependency>
 +      </dependencies>
 +      
 +      <build>
 +        <plugins>
 +          <!-- Adds Activiti test content -->
 +          <plugin>
 +            <groupId>org.codehaus.mojo</groupId>
 +            <artifactId>xml-maven-plugin</artifactId>
 +            <inherited>true</inherited>
 +            <executions>
 +              <execution>
 +                <phase>prepare-package</phase>
 +                <goals>
 +                  <goal>transform</goal>
 +                </goals>
 +              </execution>
 +            </executions>
 +            <configuration>
 +              <transformationSets>
 +                <transformationSet>
 +                  <dir>${project.build.directory}/classes</dir>
 +                  <includes>
 +                    <include>content.xml</include>
 +                  </includes>
 +                  <outputDir>${project.build.directory}/classes</outputDir>
 +                  <stylesheet>${basedir}/src/test/resources/addActivitiToContent.xsl</stylesheet>
 +                  <outputProperties>
 +                    <outputProperty>
 +                      <name>indent</name>
 +                      <value>yes</value>
 +                    </outputProperty>
 +                  </outputProperties>
 +                </transformationSet>
 +              </transformationSets>
 +            </configuration>
 +          </plugin>
 +        </plugins>
 +        
 +        <resources>
 +          <resource>
 +            <directory>src/main/resources</directory>
 +            <filtering>true</filtering>
 +            <excludes>
 +              <exclude>workflow.properties</exclude>
 +              <exclude>provisioning.properties</exclude>
 +            </excludes>
 +          </resource>
 +          <resource>
 +            <directory>src/main/resources/all</directory>
 +            <filtering>true</filtering>
 +          </resource>
 +        </resources>
 +      </build>
 +    </profile>
 +    
 +    <profile>
 +      <id>apache-release</id>
 +
 +      <build>
 +        <plugins>
 +          <plugin>
 +            <groupId>org.apache.maven.plugins</groupId>
 +            <artifactId>maven-deploy-plugin</artifactId>
 +            <configuration>
 +              <skip>true</skip>
 +            </configuration>
 +          </plugin>
 +        </plugins>
 +      </build>
 +    </profile>
 +
 +  </profiles>
 +</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/d2cc18c3/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ExceptionMapperITCase.java
----------------------------------------------------------------------
diff --cc fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ExceptionMapperITCase.java
index 0000000,0000000..25b0667
new file mode 100644
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ExceptionMapperITCase.java
@@@ -1,0 -1,0 +1,117 @@@
++/*
++ * 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.fit.core.reference;
++
++import java.io.IOException;
++import java.io.InputStream;
++import java.util.Properties;
++import org.apache.commons.io.IOUtils;
++import org.apache.syncope.common.lib.to.PlainSchemaTO;
++import org.apache.syncope.common.lib.to.RoleTO;
++import org.apache.syncope.common.lib.to.UserTO;
++import org.apache.syncope.common.lib.types.AttrSchemaType;
++import org.apache.syncope.common.lib.types.AttributableType;
++import org.apache.syncope.common.lib.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 ExceptionMapperITCase extends AbstractITCase {
++
++    private static final Properties props = new Properties();
++
++    @BeforeClass
++    public static void setUpErrorMessages() throws IOException {
++        InputStream propStream = null;
++        try {
++            propStream = ExceptionMapperITCase.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
++        PlainSchemaTO schemaTO = new PlainSchemaTO();
++        String schema_UID = getUUIDString();
++        schemaTO.setKey("unique" + schema_UID);
++        schemaTO.setType(AttrSchemaType.String);
++        schemaTO.setUniqueConstraint(true);
++        createSchema(AttributableType.USER, SchemaType.PLAIN, 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.getPlainAttrs().add(attrTO("userId", userId_1));
++        userTO_1.getPlainAttrs().add(attrTO("fullname", userId_1));
++        userTO_1.getPlainAttrs().add(attrTO("surname", userId_1));
++        userTO_1.getPlainAttrs().add(attrTO("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.getPlainAttrs().add(attrTO("userId", userId_2));
++        userTO_2.getPlainAttrs().add(attrTO("fullname", userId_2));
++        userTO_2.getPlainAttrs().add(attrTO("surname", userId_2));
++        userTO_2.getPlainAttrs().add(attrTO("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 + "]");
++        }
++    }
++
++}