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 + "]");
++ }
++ }
++
++}