You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2015/10/23 12:29:02 UTC

[01/54] [abbrv] syncope git commit: [SYNCOPE-710] Merge from 1_2_X

Repository: syncope
Updated Branches:
  refs/heads/SYNCOPE-156 13f96e068 -> 973cd50fe


http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirAttrITCase.java
----------------------------------------------------------------------
diff --cc fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirAttrITCase.java
index 0ceceda,0000000..1856eee
mode 100644,000000..100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirAttrITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirAttrITCase.java
@@@ -1,676 -1,0 +1,676 @@@
 +/*
 + * 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 static org.junit.Assert.assertEquals;
 +import static org.junit.Assert.assertFalse;
 +import static org.junit.Assert.assertNotNull;
 +import static org.junit.Assert.assertTrue;
 +
 +import java.util.Locale;
 +import java.util.Map;
 +import org.apache.commons.collections4.CollectionUtils;
 +import org.apache.commons.collections4.Predicate;
 +import org.apache.commons.lang3.SerializationUtils;
 +import org.apache.syncope.common.lib.patch.AttrPatch;
 +import org.apache.syncope.common.lib.patch.PasswordPatch;
 +import org.apache.syncope.common.lib.patch.StatusPatch;
 +import org.apache.syncope.common.lib.patch.StringPatchItem;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.common.lib.to.AttrTO;
 +import org.apache.syncope.common.lib.to.ConnInstanceTO;
 +import org.apache.syncope.common.lib.to.ConnObjectTO;
 +import org.apache.syncope.common.lib.to.MappingItemTO;
 +import org.apache.syncope.common.lib.to.MappingTO;
 +import org.apache.syncope.common.lib.to.MembershipTO;
 +import org.apache.syncope.common.lib.to.ResourceTO;
 +import org.apache.syncope.common.lib.to.GroupTO;
 +import org.apache.syncope.common.lib.to.ProvisionTO;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.ConnConfProperty;
 +import org.apache.syncope.common.lib.types.IntMappingType;
 +import org.apache.syncope.common.lib.types.MappingPurpose;
 +import org.apache.syncope.common.lib.types.PatchOperation;
 +import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
 +import org.apache.syncope.common.lib.types.StatusPatchType;
 +import org.apache.syncope.common.rest.api.service.ResourceService;
 +import org.identityconnectors.framework.common.objects.ObjectClass;
 +import org.junit.FixMethodOrder;
 +import org.junit.Test;
 +import org.junit.runners.MethodSorters;
 +import org.springframework.jdbc.core.JdbcTemplate;
 +
 +@FixMethodOrder(MethodSorters.JVM)
 +public class VirAttrITCase extends AbstractITCase {
 +
 +    @Test
 +    public void issueSYNCOPE16() {
 +        UserTO userTO = UserITCase.getUniqueSampleTO("issue16@apache.org");
 +
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(8L).build());
 +
 +        // 1. create user
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +
 +        // 2. check for virtual attribute value
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertEquals("virtualvalue", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(actual.getKey());
 +        userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "virtualupdated"));
 +
 +        // 3. update virtual attribute
 +        actual = updateUser(userPatch);
 +        assertNotNull(actual);
 +
 +        // 4. check for virtual attribute value
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertEquals("virtualupdated", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE260() {
 +        // ----------------------------------
 +        // create user and check virtual attribute value propagation
 +        // ----------------------------------
 +        UserTO userTO = UserITCase.getUniqueSampleTO("260@a.com");
 +        userTO.getResources().add(RESOURCE_NAME_WS2);
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +        assertFalse(userTO.getPropagationStatusTOs().isEmpty());
 +        assertEquals(RESOURCE_NAME_WS2, userTO.getPropagationStatusTOs().get(0).getResource());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +
 +        ConnObjectTO connObjectTO =
 +                resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
 +        assertNotNull(connObjectTO);
 +        assertEquals("virtualvalue", connObjectTO.getPlainAttrMap().get("NAME").getValues().get(0));
 +        // ----------------------------------
 +
 +        // ----------------------------------
 +        // update user virtual attribute and check virtual attribute value update propagation
 +        // ----------------------------------
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "virtualvalue2"));
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO);
 +        assertFalse(userTO.getPropagationStatusTOs().isEmpty());
 +        assertEquals("ws-target-resource-2", userTO.getPropagationStatusTOs().get(0).getResource());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +
 +        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
 +        assertNotNull(connObjectTO);
 +        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("NAME").getValues().get(0));
 +        // ----------------------------------
 +
 +        // ----------------------------------
 +        // suspend/reactivate user and check virtual attribute value (unchanged)
 +        // ----------------------------------
 +        StatusPatch statusPatch = new StatusPatch();
 +        statusPatch.setKey(userTO.getKey());
 +        statusPatch.setType(StatusPatchType.SUSPEND);
 +        userTO = userService.status(statusPatch).readEntity(UserTO.class);
 +        assertEquals("suspended", userTO.getStatus());
 +
 +        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
 +        assertNotNull(connObjectTO);
 +        assertFalse(connObjectTO.getPlainAttrMap().get("NAME").getValues().isEmpty());
 +        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("NAME").getValues().get(0));
 +
 +        statusPatch = new StatusPatch();
 +        statusPatch.setKey(userTO.getKey());
 +        statusPatch.setType(StatusPatchType.REACTIVATE);
 +        userTO = userService.status(statusPatch).readEntity(UserTO.class);
 +        assertEquals("active", userTO.getStatus());
 +
 +        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
 +        assertNotNull(connObjectTO);
 +        assertFalse(connObjectTO.getPlainAttrMap().get("NAME").getValues().isEmpty());
 +        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("NAME").getValues().get(0));
 +        // ----------------------------------
 +
 +        // ----------------------------------
 +        // update user attribute and check virtual attribute value (unchanged)
 +        // ----------------------------------
 +        userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.getPlainAttrs().add(attrAddReplacePatch("surname", "Surname2"));
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO);
 +        assertFalse(userTO.getPropagationStatusTOs().isEmpty());
 +        assertEquals(RESOURCE_NAME_WS2, userTO.getPropagationStatusTOs().get(0).getResource());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +
 +        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
 +        assertNotNull(connObjectTO);
 +        assertEquals("Surname2", connObjectTO.getPlainAttrMap().get("SURNAME").getValues().get(0));
 +
 +        // attribute "name" mapped on virtual attribute "virtualdata" shouldn't be changed
 +        assertFalse(connObjectTO.getPlainAttrMap().get("NAME").getValues().isEmpty());
 +        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("NAME").getValues().get(0));
 +        // ----------------------------------
 +
 +        // ----------------------------------
 +        // remove user virtual attribute and check virtual attribute value (reset)
 +        // ----------------------------------
 +        userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.getVirAttrs().add(new AttrPatch.Builder().
 +                operation(PatchOperation.DELETE).
 +                attrTO(new AttrTO.Builder().schema("virtualdata").build()).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO);
 +        assertTrue(userTO.getVirAttrs().isEmpty());
 +        assertFalse(userTO.getPropagationStatusTOs().isEmpty());
 +        assertEquals(RESOURCE_NAME_WS2, userTO.getPropagationStatusTOs().get(0).getResource());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +
 +        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
 +        assertNotNull(connObjectTO);
 +
 +        // attribute "name" mapped on virtual attribute "virtualdata" should be reset
 +        assertTrue(connObjectTO.getPlainAttrMap().get("NAME").getValues() == null
 +                || connObjectTO.getPlainAttrMap().get("NAME").getValues().isEmpty());
 +        // ----------------------------------
 +    }
 +
 +    @Test
 +    public void virAttrCache() {
 +        UserTO userTO = UserITCase.getUniqueSampleTO("virattrcache@apache.org");
 +        userTO.getVirAttrs().clear();
 +
 +        AttrTO virAttrTO = new AttrTO();
 +        virAttrTO.setSchema("virtualdata");
 +        virAttrTO.getValues().add("virattrcache");
 +        userTO.getVirAttrs().add(virAttrTO);
 +
 +        userTO.getMemberships().clear();
 +        userTO.getResources().clear();
 +        userTO.getResources().add(RESOURCE_NAME_DBVIRATTR);
 +
 +        // 1. create user
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +
 +        // 2. check for virtual attribute value
 +        actual = userService.read(actual.getKey());
 +        assertEquals("virattrcache", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
 +
 +        // 3. update virtual attribute directly
 +        JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
 +
 +        String value = jdbcTemplate.queryForObject(
 +                "SELECT USERNAME FROM testsync WHERE ID=?", String.class, actual.getKey());
 +        assertEquals("virattrcache", value);
 +
 +        jdbcTemplate.update("UPDATE testsync set USERNAME='virattrcache2' WHERE ID=?", actual.getKey());
 +
 +        value = jdbcTemplate.queryForObject(
 +                "SELECT USERNAME FROM testsync WHERE ID=?", String.class, actual.getKey());
 +        assertEquals("virattrcache2", value);
 +
 +        // 4. check for cached attribute value
 +        actual = userService.read(actual.getKey());
 +        assertEquals("virattrcache", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(actual.getKey());
 +        userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "virtualupdated"));
 +
 +        // 5. update virtual attribute
 +        actual = updateUser(userPatch);
 +        assertNotNull(actual);
 +
 +        // 6. check for virtual attribute value
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertEquals("virtualupdated", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE397() {
 +        ResourceTO csv = resourceService.read(RESOURCE_NAME_CSV);
 +        MappingTO origMapping = SerializationUtils.clone(csv.getProvisions().get(0).getMapping());
 +        try {
 +            // change mapping of resource-csv
 +            assertNotNull(origMapping);
 +            for (MappingItemTO item : csv.getProvisions().get(0).getMapping().getItems()) {
 +                if ("email".equals(item.getIntAttrName())) {
 +                    // unset internal attribute mail and set virtual attribute virtualdata as mapped to external email
 +                    item.setIntMappingType(IntMappingType.UserVirtualSchema);
 +                    item.setIntAttrName("virtualdata");
 +                    item.setPurpose(MappingPurpose.BOTH);
 +                    item.setExtAttrName("email");
 +                }
 +            }
 +
 +            resourceService.update(csv);
 +            csv = resourceService.read(RESOURCE_NAME_CSV);
 +            assertNotNull(csv.getProvisions().get(0).getMapping());
 +
 +            boolean found = false;
 +            for (MappingItemTO item : csv.getProvisions().get(0).getMapping().getItems()) {
 +                if ("email".equals(item.getExtAttrName()) && "virtualdata".equals(item.getIntAttrName())) {
 +                    found = true;
 +                }
 +            }
 +
 +            assertTrue(found);
 +
 +            // create a new user
-             UserTO userTO = UserITCase.getUniqueSampleTO("syncope397@syncope.apache.org");
++            UserTO userTO = UserITCase.getUniqueSampleTO("397@syncope.apache.org");
 +            userTO.getAuxClasses().add("csv");
 +            userTO.getResources().clear();
 +            userTO.getMemberships().clear();
 +            userTO.getDerAttrs().clear();
 +            userTO.getVirAttrs().clear();
 +
 +            userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +            userTO.getDerAttrs().add(attrTO("cn", null));
 +            userTO.getVirAttrs().add(attrTO("virtualdata", "test@testone.org"));
 +            // assign resource-csv to user
 +            userTO.getResources().add(RESOURCE_NAME_CSV);
 +            // save user
 +            UserTO created = createUser(userTO);
 +            // make std controls about user
 +            assertNotNull(created);
 +            assertTrue(RESOURCE_NAME_CSV.equals(created.getResources().iterator().next()));
 +            assertEquals("test@testone.org", created.getVirAttrs().iterator().next().getValues().get(0));
 +
 +            // update user
 +            UserTO toBeUpdated = userService.read(created.getKey());
 +            UserPatch userPatch = new UserPatch();
 +            userPatch.setKey(toBeUpdated.getKey());
 +            userPatch.setPassword(new PasswordPatch.Builder().value("password234").build());
 +            // assign new resource to user
 +            userPatch.getResources().add(new StringPatchItem.Builder().
 +                    operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_WS2).build());
 +            // modify virtual attribute
 +            userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "test@testoneone.com"));
 +
 +            // check Syncope change password
 +            userPatch.setPassword(new PasswordPatch.Builder().
 +                    value("password234").
 +                    onSyncope(true).
 +                    resource(RESOURCE_NAME_WS2).
 +                    build());
 +
 +            toBeUpdated = updateUser(userPatch);
 +            assertNotNull(toBeUpdated);
-             assertEquals("test@testoneone.com", toBeUpdated.getVirAttrs().iterator().next().getValues().get(0));
++            assertTrue(toBeUpdated.getVirAttrs().iterator().next().getValues().contains("test@testoneone.com"));
 +            // check if propagates correctly with assertEquals on size of tasks list
 +            assertEquals(2, toBeUpdated.getPropagationStatusTOs().size());
 +        } finally {
 +            // restore mapping of resource-csv
 +            csv.getProvisions().get(0).setMapping(origMapping);
 +            resourceService.update(csv);
 +        }
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE442() {
 +        UserTO userTO = UserITCase.getUniqueSampleTO("syncope442@apache.org");
 +        userTO.getVirAttrs().clear();
 +
 +        AttrTO virAttrTO = new AttrTO();
 +        virAttrTO.setSchema("virtualdata");
 +        virAttrTO.getValues().add("virattrcache");
 +        userTO.getVirAttrs().add(virAttrTO);
 +
 +        userTO.getMemberships().clear();
 +        userTO.getResources().clear();
 +        userTO.getResources().add(RESOURCE_NAME_DBVIRATTR);
 +
 +        // 1. create user
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +
 +        // 2. check for virtual attribute value
 +        actual = userService.read(actual.getKey());
 +        assertEquals("virattrcache", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
 +
 +        // ----------------------------------------
 +        // 3. force cache expiring without any modification
 +        // ----------------------------------------
 +        String jdbcURL = null;
 +        ConnInstanceTO connInstanceTO = connectorService.readByResource(
 +                RESOURCE_NAME_DBVIRATTR, Locale.ENGLISH.getLanguage());
 +        for (ConnConfProperty prop : connInstanceTO.getConfiguration()) {
 +            if ("jdbcUrlTemplate".equals(prop.getSchema().getName())) {
 +                jdbcURL = prop.getValues().iterator().next().toString();
 +                prop.getValues().clear();
 +                prop.getValues().add("jdbc:h2:tcp://localhost:9092/xxx");
 +            }
 +        }
 +
 +        connectorService.update(connInstanceTO);
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(actual.getKey());
 +        userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "virtualupdated"));
 +
 +        actual = updateUser(userPatch);
 +        assertNotNull(actual);
 +        // ----------------------------------------
 +
 +        // ----------------------------------------
 +        // 4. update virtual attribute
 +        // ----------------------------------------
 +        final JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
 +
 +        String value = jdbcTemplate.queryForObject(
 +                "SELECT USERNAME FROM testsync WHERE ID=?", String.class, actual.getKey());
 +        assertEquals("virattrcache", value);
 +
 +        jdbcTemplate.update("UPDATE testsync set USERNAME='virattrcache2' WHERE ID=?", actual.getKey());
 +
 +        value = jdbcTemplate.queryForObject(
 +                "SELECT USERNAME FROM testsync WHERE ID=?", String.class, actual.getKey());
 +        assertEquals("virattrcache2", value);
 +        // ----------------------------------------
 +
 +        actual = userService.read(actual.getKey());
 +        assertEquals("virattrcache", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
 +
 +        // ----------------------------------------
 +        // 5. restore connector
 +        // ----------------------------------------
 +        for (ConnConfProperty prop : connInstanceTO.getConfiguration()) {
 +            if ("jdbcUrlTemplate".equals(prop.getSchema().getName())) {
 +                prop.getValues().clear();
 +                prop.getValues().add(jdbcURL);
 +            }
 +        }
 +
 +        connectorService.update(connInstanceTO);
 +        // ----------------------------------------
 +
 +        actual = userService.read(actual.getKey());
 +        assertEquals("virattrcache2", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE436() {
 +        UserTO userTO = UserITCase.getUniqueSampleTO("syncope436@syncope.apache.org");
 +        userTO.getMemberships().clear();
 +        userTO.getResources().clear();
 +        userTO.getResources().add(RESOURCE_NAME_LDAP);
 +        userTO.getVirAttrs().add(attrTO("virtualReadOnly", "readOnly"));
 +        userTO = createUser(userTO);
 +        //Finding no values because the virtual attribute is readonly 
 +        assertTrue(userTO.getVirAttrMap().get("virtualReadOnly").getValues().isEmpty());
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE453() {
 +        final String resourceName = "issueSYNCOPE453-Res-" + getUUIDString();
 +        final String groupName = "issueSYNCOPE453-Group-" + getUUIDString();
 +
 +        // -------------------------------------------
 +        // Create a resource ad-hoc
 +        // -------------------------------------------
 +        ResourceTO resourceTO = new ResourceTO();
 +
 +        resourceTO.setKey(resourceName);
 +        resourceTO.setConnector(107L);
 +
 +        ProvisionTO provisionTO = new ProvisionTO();
 +        provisionTO.setAnyType(AnyTypeKind.USER.name());
 +        provisionTO.setObjectClass(ObjectClass.ACCOUNT_NAME);
 +        resourceTO.getProvisions().add(provisionTO);
 +
 +        MappingTO mapping = new MappingTO();
 +        provisionTO.setMapping(mapping);
 +
 +        MappingItemTO item = new MappingItemTO();
 +        item.setIntAttrName("aLong");
 +        item.setIntMappingType(IntMappingType.UserPlainSchema);
 +        item.setExtAttrName("ID");
 +        item.setPurpose(MappingPurpose.PROPAGATION);
 +        item.setConnObjectKey(true);
 +        mapping.setConnObjectKeyItem(item);
 +
 +        item = new MappingItemTO();
 +        item.setExtAttrName("USERNAME");
 +        item.setIntAttrName("username");
 +        item.setIntMappingType(IntMappingType.Username);
 +        item.setPurpose(MappingPurpose.PROPAGATION);
 +        mapping.getItems().add(item);
 +
 +        item = new MappingItemTO();
 +        item.setExtAttrName("EMAIL");
 +        item.setIntAttrName("rvirtualdata");
 +        item.setIntMappingType(IntMappingType.GroupVirtualSchema);
 +        item.setPurpose(MappingPurpose.PROPAGATION);
 +        mapping.getItems().add(item);
 +
 +        assertNotNull(getObject(
 +                resourceService.create(resourceTO).getLocation(), ResourceService.class, ResourceTO.class));
 +        // -------------------------------------------
 +
 +        // -------------------------------------------
 +        // Create a VirAttrITCase ad-hoc
 +        // -------------------------------------------
 +        GroupTO groupTO = new GroupTO();
 +        groupTO.setName(groupName);
 +        groupTO.setRealm("/");
 +        groupTO.getVirAttrs().add(attrTO("rvirtualdata", "ml@group.it"));
 +        groupTO.getResources().add(RESOURCE_NAME_LDAP);
 +        groupTO = createGroup(groupTO);
 +        assertEquals(1, groupTO.getVirAttrs().size());
 +        assertEquals("ml@group.it", groupTO.getVirAttrs().iterator().next().getValues().get(0));
 +        // -------------------------------------------
 +
 +        // -------------------------------------------
 +        // Create new user
 +        // -------------------------------------------
 +        UserTO userTO = UserITCase.getUniqueSampleTO("syncope453@syncope.apache.org");
 +        userTO.getPlainAttrs().add(attrTO("aLong", "123"));
 +        userTO.getResources().clear();
 +        userTO.getResources().add(resourceName);
 +        userTO.getVirAttrs().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getMemberships().clear();
 +
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(groupTO.getKey()).build());
 +
 +        userTO = createUser(userTO);
 +        assertEquals(2, userTO.getPropagationStatusTOs().size());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(1).getStatus());
 +
 +        JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
 +
 +        final Map<String, Object> actuals = jdbcTemplate.queryForMap(
 +                "SELECT id, surname, email FROM testsync WHERE id=?",
 +                new Object[] { Integer.parseInt(userTO.getPlainAttrMap().get("aLong").getValues().get(0)) });
 +
 +        assertEquals(userTO.getPlainAttrMap().get("aLong").getValues().get(0), actuals.get("id").toString());
 +        assertEquals("ml@group.it", actuals.get("email"));
 +        // -------------------------------------------
 +
 +        // -------------------------------------------
 +        // Delete resource and group ad-hoc
 +        // -------------------------------------------
 +        resourceService.delete(resourceName);
 +        groupService.delete(groupTO.getKey());
 +        // -------------------------------------------
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE459() {
 +        UserTO userTO = UserITCase.getUniqueSampleTO("syncope459@apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getVirAttrs().clear();
 +
 +        AttrTO virtualReadOnly = attrTO("virtualReadOnly", "");
 +        virtualReadOnly.getValues().clear();
 +
 +        userTO.getVirAttrs().add(virtualReadOnly);
 +
 +        userTO = createUser(userTO);
 +
 +        assertNotNull(userTO.getVirAttrMap().get("virtualReadOnly"));
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.getVirAttrs().add(new AttrPatch.Builder().
 +                operation(PatchOperation.ADD_REPLACE).
 +                attrTO(new AttrTO.Builder().schema("virtualdata").build()).
 +                build());
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO.getVirAttrMap().get("virtualdata"));
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE501() {
 +        // 1. create user and propagate him on resource-db-virattr
 +        UserTO userTO = UserITCase.getUniqueSampleTO("syncope501@apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getVirAttrs().clear();
 +
 +        userTO.getResources().add(RESOURCE_NAME_DBVIRATTR);
 +
 +        // virtualdata is mapped with username
 +        userTO.getVirAttrs().add(attrTO("virtualdata", "syncope501@apache.org"));
 +
 +        userTO = createUser(userTO);
 +
 +        assertNotNull(userTO.getVirAttrMap().get("virtualdata"));
 +        assertEquals("syncope501@apache.org", userTO.getVirAttrMap().get("virtualdata").getValues().get(0));
 +
 +        // 2. update virtual attribute
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        // change virtual attribute value
 +        userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "syncope501_updated@apache.org"));
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO);
 +
 +        // 3. check that user virtual attribute has really been updated 
 +        assertFalse(userTO.getVirAttrMap().get("virtualdata").getValues().isEmpty());
 +        assertEquals("syncope501_updated@apache.org", userTO.getVirAttrMap().get("virtualdata").getValues().get(0));
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE691() {
 +        final String res = RESOURCE_NAME_LDAP + "691";
 +
 +        ResourceTO ldap = resourceService.read(RESOURCE_NAME_LDAP);
 +        ldap.setKey(res);
 +
 +        try {
 +
 +            CollectionUtils.filterInverse(ldap.getProvision(AnyTypeKind.USER.name()).getMapping().getItems(),
 +                    new Predicate<MappingItemTO>() {
 +
 +                        @Override
 +                        public boolean evaluate(final MappingItemTO item) {
 +                            return "mail".equals(item.getExtAttrName());
 +                        }
 +                    });
 +
 +            final MappingItemTO mail = new MappingItemTO();
 +            // unset internal attribute mail and set virtual attribute virtualdata as mapped to external email
 +            mail.setIntMappingType(IntMappingType.UserVirtualSchema);
 +            mail.setIntAttrName("virtualdata");
 +            mail.setPurpose(MappingPurpose.BOTH);
 +            mail.setExtAttrName("mail");
 +
 +            ldap.getProvision(AnyTypeKind.USER.name()).getMapping().getItems().add(mail);
 +
 +            resourceService.create(ldap);
 +
 +            ldap = resourceService.read(res);
 +            assertNotNull(ldap.getProvision(AnyTypeKind.USER.name()).getMapping());
 +
 +            assertTrue(CollectionUtils.exists(ldap.getProvision(AnyTypeKind.USER.name()).getMapping().getItems(),
 +                    new Predicate<MappingItemTO>() {
 +
 +                        @Override
 +                        public boolean evaluate(final MappingItemTO item) {
 +                            return "mail".equals(item.getExtAttrName()) && "virtualdata".equals(item.getIntAttrName());
 +                        }
 +                    }));
 +
 +            // create a new user
 +            UserTO userTO = UserITCase.getUniqueSampleTO("syncope691@syncope.apache.org");
 +            userTO.getResources().clear();
 +            userTO.getMemberships().clear();
 +            userTO.getDerAttrs().clear();
 +            userTO.getVirAttrs().clear();
 +
 +            final AttrTO emailTO = new AttrTO();
 +            emailTO.setSchema("virtualdata");
 +            emailTO.getValues().add("test@issue691.dom1.org");
 +            emailTO.getValues().add("test@issue691.dom2.org");
 +
 +            userTO.getVirAttrs().add(emailTO);
 +            // assign resource-ldap691 to user
 +            userTO.getResources().add(res);
 +            // save user
 +            UserTO created = createUser(userTO);
 +            // make std controls about user
 +            assertNotNull(created);
 +            assertTrue(res.equals(created.getResources().iterator().next()));
 +
 +            assertEquals(2, created.getVirAttrs().iterator().next().getValues().size(), 0);
 +            assertTrue(created.getVirAttrs().iterator().next().getValues().contains("test@issue691.dom1.org"));
 +            assertTrue(created.getVirAttrs().iterator().next().getValues().contains("test@issue691.dom2.org"));
 +
 +            // update user
 +            UserPatch userPatch = new UserPatch();
 +            userPatch.setKey(created.getKey());
 +            // modify virtual attribute
 +            userPatch.getVirAttrs().add(new AttrPatch.Builder().
 +                    operation(PatchOperation.ADD_REPLACE).
 +                    attrTO(new AttrTO.Builder().schema("virtualdata").
 +                            value("test@issue691.dom3.org").
 +                            value("test@issue691.dom4.org").
 +                            build()).build());
 +
 +            UserTO updated = updateUser(userPatch);
 +            assertNotNull(updated);
 +            assertEquals(2, updated.getVirAttrs().iterator().next().getValues().size(), 0);
 +            assertTrue(updated.getVirAttrs().iterator().next().getValues().contains("test@issue691.dom3.org"));
 +            assertTrue(updated.getVirAttrs().iterator().next().getValues().contains("test@issue691.dom4.org"));
 +        } finally {
 +            try {
 +                resourceService.delete(res);
 +            } catch (Exception ignore) {
 +                // ignore
 +            }
 +        }
 +    }
 +
 +}


[15/54] [abbrv] syncope git commit: Upgrading surefire, failsafe and checkstyle plugins

Posted by fm...@apache.org.
Upgrading surefire, failsafe and checkstyle plugins


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

Branch: refs/heads/SYNCOPE-156
Commit: 503097da8cddb197db8f54378f3721c46f32fb3f
Parents: 03c9bc2
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Mon Oct 19 15:00:42 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Mon Oct 19 15:00:42 2015 +0200

----------------------------------------------------------------------
 pom.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/503097da/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index e4b3787..4ef0802 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1082,7 +1082,7 @@ under the License.
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-surefire-plugin</artifactId>
-          <version>2.18.1</version>
+          <version>2.19</version>
           <configuration>
             <redirectTestOutputToFile>true</redirectTestOutputToFile>
             <encoding>utf-8</encoding>
@@ -1106,7 +1106,7 @@ under the License.
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-failsafe-plugin</artifactId>
-          <version>2.18.1</version>
+          <version>2.19</version>
           <configuration>
             <redirectTestOutputToFile>true</redirectTestOutputToFile>
             <encoding>utf-8</encoding>
@@ -1204,7 +1204,7 @@ under the License.
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-checkstyle-plugin</artifactId>
-          <version>2.15</version>
+          <version>2.17</version>
           <dependencies>
             <dependency>
               <groupId>org.apache.syncope</groupId>


[53/54] [abbrv] syncope git commit: refactoring of the task stack , SYNCOPE-158

Posted by fm...@apache.org.
refactoring of the task stack , SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 73f73f20692910e6f0c2acf27d5d8bd7982e6b6c
Parents: 23d8047
Author: massi <ma...@tirasa.net>
Authored: Thu Oct 22 17:36:58 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Thu Oct 22 17:37:31 2015 +0200

----------------------------------------------------------------------
 .../org/apache/syncope/client/cli/Input.java    |   4 +
 .../client/cli/commands/TaskCommand.java        | 585 -------------------
 .../cli/commands/task/AbstractTaskCommand.java  |  30 +
 .../client/cli/commands/task/TaskCommand.java   | 140 +++++
 .../client/cli/commands/task/TaskDelete.java    |  58 ++
 .../client/cli/commands/task/TaskExecute.java   |  66 +++
 .../cli/commands/task/TaskExecutionDelete.java  |  58 ++
 .../cli/commands/task/TaskExecutionRead.java    |  58 ++
 .../client/cli/commands/task/TaskList.java      |  59 ++
 .../client/cli/commands/task/TaskRead.java      |  60 ++
 .../cli/commands/task/TaskResultManager.java    | 222 +++++++
 .../cli/commands/task/TaskRunningJobs.java      |  34 ++
 .../cli/commands/task/TaskScheduledJobs.java    |  34 ++
 13 files changed, 823 insertions(+), 585 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/Input.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/Input.java b/client/cli/src/main/java/org/apache/syncope/client/cli/Input.java
index c53eefd..9314187 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/Input.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/Input.java
@@ -67,6 +67,10 @@ public class Input {
     public String firstParameter() {
         return parameters[0];
     }
+    
+    public String secondParameter() {
+        return parameters[1];
+    }
 
     public String lastParameter() {
         return parameters[parameters.length - 1];

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
deleted file mode 100644
index deb00bf..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
+++ /dev/null
@@ -1,585 +0,0 @@
-/*
- * 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.cli.commands;
-
-import org.apache.syncope.client.cli.commands.logger.LoggerCommand;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import javax.xml.ws.WebServiceException;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.cli.Command;
-import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.SyncopeServices;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.util.CommandUtils;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.AbstractTaskTO;
-import org.apache.syncope.common.lib.to.AnyTO;
-import org.apache.syncope.common.lib.to.NotificationTaskTO;
-import org.apache.syncope.common.lib.to.PropagationTaskTO;
-import org.apache.syncope.common.lib.to.PushTaskTO;
-import org.apache.syncope.common.lib.to.SchedTaskTO;
-import org.apache.syncope.common.lib.to.SyncTaskTO;
-import org.apache.syncope.common.lib.to.TaskExecTO;
-import org.apache.syncope.common.lib.types.JobStatusType;
-import org.apache.syncope.common.lib.types.TaskType;
-import org.apache.syncope.common.rest.api.beans.TaskQuery;
-import org.apache.syncope.common.rest.api.service.TaskService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Command(name = "task")
-public class TaskCommand extends AbstractCommand {
-
-    private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
-
-    private static final String HELP_MESSAGE = "Usage: task [options]\n"
-            + "  Options:\n"
-            + "    --help \n"
-            + "    --list-task \n"
-            + "       Syntax: --list-task {TASK-TYPE} \n"
-            + "          Task type: NOTIFICATION / PROPAGATION / PUSH / SCHEDULED / SYNCHRONIZATION\n"
-            + "    --list-running-jobs \n"
-            + "    --list-scheduled-jobs \n"
-            + "    --read \n"
-            + "       Syntax: --read {TASK-ID} {TASK-ID} [...]\n"
-            + "    --read-execution \n"
-            + "       Syntax: --read-execution {TASK-EXEC-ID} {TASK-EXEC-ID} [...]\n"
-            + "    --delete \n"
-            + "       Syntax: --delete {TASK-ID} {TASK-ID} [...]\n"
-            + "    --delete-execution \n"
-            + "       Syntax: --delete-execution {TASK-EXEC-ID} {TASK-EXEC-ID} [...]\n"
-            + "    --execute \n"
-            + "       Syntax: --execute {TASK-ID} {DRY-RUN}"
-            + "          Dry run: true / false";
-    
-    @Override
-    public void execute(final Input input) {
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
-        final String[] parameters = input.getParameters();
-
-        if (StringUtils.isBlank(input.getOption())) {
-            input.setOption(Options.HELP.getOptionName());
-        }
-
-        final TaskService taskService = SyncopeServices.get(TaskService.class);
-        switch (Options.fromName(input.getOption())) {
-            case LIST_TASK:
-                final String listTaskErrorMessage = "task --list-task {TASK-TYPE}\n"
-                        + "   Task type: NOTIFICATION / PROPAGATION / PUSH / SCHEDULED / SYNCHRONIZATION";
-                if (parameters.length == 1) {
-                    try {
-                        final TaskType taskType = TaskType.valueOf(parameters[0]);
-                        for (final AbstractTaskTO taskTO : taskService.list(taskType, new TaskQuery()).getResult()) {
-                            switch (taskType) {
-                                case NOTIFICATION:
-                                    final NotificationTaskTO notificationTaskTO = (NotificationTaskTO) taskTO;
-                                    System.out.println("");
-                                    System.out.println(" - Notification task key: " + notificationTaskTO.getKey());
-                                    System.out.println("     executed: " + notificationTaskTO.isExecuted());
-                                    System.out.println("     sender: " + notificationTaskTO.getSender());
-                                    System.out.println("     subjetc: " + notificationTaskTO.getSubject());
-                                    System.out.println("     text body: " + notificationTaskTO.getTextBody());
-                                    System.out.println("     html body: " + notificationTaskTO.getHtmlBody());
-                                    System.out.println("     latest execution status: "
-                                            + notificationTaskTO.getLatestExecStatus());
-                                    System.out.println("     start date: " + notificationTaskTO.getStartDate());
-                                    System.out.println("     end date: " + notificationTaskTO.getEndDate());
-                                    System.out.println("     recipients: " + notificationTaskTO.getRecipients());
-                                    System.out.println("     trace level: " + notificationTaskTO.getTraceLevel());
-                                    for (final TaskExecTO taskExecTO : notificationTaskTO.getExecutions()) {
-                                        printTaskExecTO(taskExecTO);
-                                    }
-                                    System.out.println("");
-                                    break;
-                                case PROPAGATION:
-                                    final PropagationTaskTO propagationTaskTO = (PropagationTaskTO) taskTO;
-                                    System.out.println("");
-                                    System.out.println(" - Propagation task key: " + propagationTaskTO.getKey());
-                                    System.out.println("     resource: " + propagationTaskTO.getResource());
-                                    System.out.println("     any key: " + propagationTaskTO.getAnyKey());
-                                    System.out.println("     any type kind: " + propagationTaskTO.getAnyTypeKind());
-                                    System.out.println("     connector object key: "
-                                            + propagationTaskTO.getConnObjectKey());
-                                    System.out.println("     old connector object key: "
-                                            + propagationTaskTO.getOldConnObjectKey());
-                                    System.out.println("     latest execution status: "
-                                            + propagationTaskTO.getLatestExecStatus());
-                                    System.out.println("     class name: " + propagationTaskTO.getObjectClassName());
-                                    System.out.println("     xml attribute: " + propagationTaskTO.getXmlAttributes());
-                                    System.out.println("     start date: " + propagationTaskTO.getStartDate());
-                                    System.out.println("     end date: " + propagationTaskTO.getEndDate());
-                                    System.out.println("     operation: " + propagationTaskTO.getOperation());
-                                    for (final TaskExecTO taskExecTO : propagationTaskTO.getExecutions()) {
-                                        printTaskExecTO(taskExecTO);
-                                    }
-                                    System.out.println("");
-                                    break;
-                                case PUSH:
-                                    final PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
-                                    System.out.println("");
-                                    System.out.println(" - Push task key: " + pushTaskTO.getKey());
-                                    System.out.println("     name: " + pushTaskTO.getName());
-                                    System.out.println("     resource: " + pushTaskTO.getResource());
-                                    System.out.println("     cron expression: " + pushTaskTO.getCronExpression());
-                                    System.out.println("     description: " + pushTaskTO.getDescription());
-                                    System.out.println("     is perform create: " + pushTaskTO.isPerformCreate());
-                                    System.out.println("     is perform delete: " + pushTaskTO.isPerformDelete());
-                                    System.out.println("     is perform update: " + pushTaskTO.isPerformUpdate());
-                                    System.out.println("     is sync status: " + pushTaskTO.isSyncStatus());
-                                    System.out.println("     start date: " + pushTaskTO.getStartDate());
-                                    System.out.println("     end date: " + pushTaskTO.getEndDate());
-                                    System.out.println("     last execution: " + pushTaskTO.getLastExec());
-                                    System.out.println("     next execution: " + pushTaskTO.getNextExec());
-                                    System.out.println("     latest execution status: "
-                                            + pushTaskTO.getLatestExecStatus());
-                                    System.out.println("     filters: " + pushTaskTO.getFilters());
-                                    System.out.println("     delegate class: " + pushTaskTO.getJobDelegateClassName());
-                                    System.out.println("     action class: " + pushTaskTO.getActionsClassNames());
-                                    System.out.println("     matching rule: " + pushTaskTO.getMatchingRule());
-                                    System.out.println("     not matching rule: " + pushTaskTO.getUnmatchingRule());
-                                    for (final TaskExecTO taskExecTO : pushTaskTO.getExecutions()) {
-                                        printTaskExecTO(taskExecTO);
-                                    }
-                                    System.out.println("");
-                                    break;
-                                case SCHEDULED:
-                                    final SchedTaskTO schedTaskTO = (SchedTaskTO) taskTO;
-                                    System.out.println("");
-                                    System.out.println(" - Scheduled task key: " + schedTaskTO.getKey());
-                                    System.out.println("     name: " + schedTaskTO.getName());
-                                    System.out.println("     cron expression: " + schedTaskTO.getCronExpression());
-                                    System.out.println("     description: " + schedTaskTO.getDescription());
-                                    System.out.println("     start date: " + schedTaskTO.getStartDate());
-                                    System.out.println("     end date: " + schedTaskTO.getEndDate());
-                                    System.out.println("     last execution: " + schedTaskTO.getLastExec());
-                                    System.out.println("     next execution: " + schedTaskTO.getNextExec());
-                                    System.out.println("     latest execution status: "
-                                            + schedTaskTO.getLatestExecStatus());
-                                    System.out.println("     job delegate class: "
-                                            + schedTaskTO.getJobDelegateClassName());
-                                    for (final TaskExecTO taskExecTO : schedTaskTO.getExecutions()) {
-                                        printTaskExecTO(taskExecTO);
-                                    }
-                                    System.out.println("");
-                                    break;
-                                case SYNCHRONIZATION:
-                                    final SyncTaskTO syncTaskTO = (SyncTaskTO) taskTO;
-                                    System.out.println("");
-                                    System.out.println(" - Sync task key: " + syncTaskTO.getKey());
-                                    System.out.println("     name: " + syncTaskTO.getName());
-                                    System.out.println("     resource: " + syncTaskTO.getResource());
-                                    System.out.println("     realm destination: " + syncTaskTO.getDestinationRealm());
-                                    System.out.println("     cron expression: " + syncTaskTO.getCronExpression());
-                                    System.out.println("     description: " + syncTaskTO.getDescription());
-                                    System.out.println("     is full reconciliation: "
-                                            + syncTaskTO.isFullReconciliation());
-                                    System.out.println("     is perform create: " + syncTaskTO.isPerformCreate());
-                                    System.out.println("     is perform delete: " + syncTaskTO.isPerformDelete());
-                                    System.out.println("     is perform update: " + syncTaskTO.isPerformUpdate());
-                                    System.out.println("     is sync status: " + syncTaskTO.isSyncStatus());
-                                    System.out.println("     templates:");
-                                    for (Map.Entry<String, AnyTO> entrySet : syncTaskTO.getTemplates().entrySet()) {
-                                        final String key = entrySet.getKey();
-                                        final AnyTO value = entrySet.getValue();
-                                        System.out.println("        " + key + " key: " + value.getKey()
-                                                + " of realm" + value.getRealm()
-                                                + " on resource " + value.getResources());
-
-                                    }
-                                    System.out.println("     start date: " + syncTaskTO.getStartDate());
-                                    System.out.println("     end date: " + syncTaskTO.getEndDate());
-                                    System.out.println("     next execution: " + syncTaskTO.getNextExec());
-                                    System.out.println("     last execution: " + syncTaskTO.getLastExec());
-                                    System.out.println("     latest execution status: "
-                                            + syncTaskTO.getLatestExecStatus());
-                                    System.out.println("     job delegate class: "
-                                            + syncTaskTO.getJobDelegateClassName());
-                                    System.out.println("     action class name: " + syncTaskTO.getActionsClassNames());
-                                    System.out.println("     matching rule: " + syncTaskTO.getMatchingRule());
-                                    System.out.println("     unmatching rule: " + syncTaskTO.getUnmatchingRule());
-                                    for (final TaskExecTO taskExecTO : syncTaskTO.getExecutions()) {
-                                        printTaskExecTO(taskExecTO);
-                                    }
-                                    System.out.println("");
-                                    break;
-                                default:
-                                    break;
-                            }
-                        }
-                    } catch (final SyncopeClientException ex) {
-                        Messages.printMessage(ex.getMessage());
-                    } catch (final IllegalArgumentException ex) {
-                        Messages.printTypeNotValidMessage(
-                                "task", parameters[0], CommandUtils.fromEnumToArray(TaskType.class));
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(listTaskErrorMessage);
-                }
-                break;
-            case LIST_RUNNING_JOBS:
-                try {
-                    for (final TaskExecTO taskExecTO : taskService.listJobs(JobStatusType.RUNNING)) {
-                        printTaskExecTO(taskExecTO);
-                    }
-                } catch (final SyncopeClientException ex) {
-                    Messages.printMessage(ex.getMessage());
-                }
-                break;
-            case LIST_SCHEDULED_JOBS:
-                try {
-                    for (final TaskExecTO taskExecTO : taskService.listJobs(JobStatusType.SCHEDULED)) {
-                        printTaskExecTO(taskExecTO);
-                    }
-                } catch (final SyncopeClientException ex) {
-                    Messages.printMessage(ex.getMessage());
-                }
-                break;
-            case READ:
-                final String readErrorMessage = "task --read {TASK-ID} {TASK-ID} [...]";
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            final AbstractTaskTO taskTO = taskService.read(Long.valueOf(parameter));
-                            if (taskTO instanceof NotificationTaskTO) {
-                                final NotificationTaskTO notificationTaskTO = (NotificationTaskTO) taskTO;
-                                System.out.println("");
-                                System.out.println(" - Notification task key: " + notificationTaskTO.getKey());
-                                System.out.println("     executed: " + notificationTaskTO.isExecuted());
-                                System.out.println("     sender: " + notificationTaskTO.getSender());
-                                System.out.println("     subjetc: " + notificationTaskTO.getSubject());
-                                System.out.println("     text body: " + notificationTaskTO.getTextBody());
-                                System.out.println("     html body: " + notificationTaskTO.getHtmlBody());
-                                System.out.println("     latest execution status: "
-                                        + notificationTaskTO.getLatestExecStatus());
-                                System.out.println("     start date: " + notificationTaskTO.getStartDate());
-                                System.out.println("     end date: " + notificationTaskTO.getEndDate());
-                                System.out.println("     recipients: " + notificationTaskTO.getRecipients());
-                                System.out.println("     trace level: " + notificationTaskTO.getTraceLevel());
-                                for (final TaskExecTO taskExecTO : notificationTaskTO.getExecutions()) {
-                                    printTaskExecTO(taskExecTO);
-                                }
-                                System.out.println("");
-                            } else if (taskTO instanceof PropagationTaskTO) {
-                                final PropagationTaskTO propagationTaskTO = (PropagationTaskTO) taskTO;
-                                System.out.println("");
-                                System.out.println(" - Propagation task key: " + propagationTaskTO.getKey());
-                                System.out.println("     resource: " + propagationTaskTO.getResource());
-                                System.out.println("     any key: " + propagationTaskTO.getAnyKey());
-                                System.out.println("     any type kind: " + propagationTaskTO.getAnyTypeKind());
-                                System.out.println("     connector object key: "
-                                        + propagationTaskTO.getConnObjectKey());
-                                System.out.println("     old connector object key: "
-                                        + propagationTaskTO.getOldConnObjectKey());
-                                System.out.println("     latest execution status: "
-                                        + propagationTaskTO.getLatestExecStatus());
-                                System.out.println("     class name: " + propagationTaskTO.getObjectClassName());
-                                System.out.println("     xml attribute: " + propagationTaskTO.getXmlAttributes());
-                                System.out.println("     start date: " + propagationTaskTO.getStartDate());
-                                System.out.println("     end date: " + propagationTaskTO.getEndDate());
-                                System.out.println("     operation: " + propagationTaskTO.getOperation());
-                                for (final TaskExecTO taskExecTO : propagationTaskTO.getExecutions()) {
-                                    printTaskExecTO(taskExecTO);
-                                }
-                                System.out.println("");
-                            } else if (taskTO instanceof PushTaskTO) {
-                                final PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
-                                System.out.println("");
-                                System.out.println(" - Push task key: " + pushTaskTO.getKey());
-                                System.out.println("     name: " + pushTaskTO.getName());
-                                System.out.println("     resource: " + pushTaskTO.getResource());
-                                System.out.println("     cron expression: " + pushTaskTO.getCronExpression());
-                                System.out.println("     description: " + pushTaskTO.getDescription());
-                                System.out.println("     is perform create: " + pushTaskTO.isPerformCreate());
-                                System.out.println("     is perform delete: " + pushTaskTO.isPerformDelete());
-                                System.out.println("     is perform update: " + pushTaskTO.isPerformUpdate());
-                                System.out.println("     is sync status: " + pushTaskTO.isSyncStatus());
-                                System.out.println("     start date: " + pushTaskTO.getStartDate());
-                                System.out.println("     end date: " + pushTaskTO.getEndDate());
-                                System.out.println("     last execution: " + pushTaskTO.getLastExec());
-                                System.out.println("     next execution: " + pushTaskTO.getNextExec());
-                                System.out.println("     latest execution status: "
-                                        + pushTaskTO.getLatestExecStatus());
-                                System.out.println("     filters: " + pushTaskTO.getFilters());
-                                System.out.println("     delegate class: " + pushTaskTO.getJobDelegateClassName());
-                                System.out.println("     action class: " + pushTaskTO.getActionsClassNames());
-                                System.out.println("     matching rule: " + pushTaskTO.getMatchingRule());
-                                System.out.println("     not matching rule: " + pushTaskTO.getUnmatchingRule());
-                                for (final TaskExecTO taskExecTO : pushTaskTO.getExecutions()) {
-                                    printTaskExecTO(taskExecTO);
-                                }
-                                System.out.println("");
-                            } else if (taskTO instanceof SchedTaskTO) {
-                                final SchedTaskTO schedTaskTO = (SchedTaskTO) taskTO;
-                                System.out.println("");
-                                System.out.println(" - Scheduled task key: " + schedTaskTO.getKey());
-                                System.out.println("     name: " + schedTaskTO.getName());
-                                System.out.println("     cron expression: " + schedTaskTO.getCronExpression());
-                                System.out.println("     description: " + schedTaskTO.getDescription());
-                                System.out.println("     start date: " + schedTaskTO.getStartDate());
-                                System.out.println("     end date: " + schedTaskTO.getEndDate());
-                                System.out.println("     last execution: " + schedTaskTO.getLastExec());
-                                System.out.println("     next execution: " + schedTaskTO.getNextExec());
-                                System.out.println("     latest execution status: "
-                                        + schedTaskTO.getLatestExecStatus());
-                                System.out.println("     job delegate class: "
-                                        + schedTaskTO.getJobDelegateClassName());
-                                for (final TaskExecTO taskExecTO : schedTaskTO.getExecutions()) {
-                                    printTaskExecTO(taskExecTO);
-                                }
-                                System.out.println("");
-                            } else if (taskTO instanceof SyncTaskTO) {
-                                final SyncTaskTO syncTaskTO = (SyncTaskTO) taskTO;
-                                System.out.println("");
-                                System.out.println(" - Sync task key: " + syncTaskTO.getKey());
-                                System.out.println("     name: " + syncTaskTO.getName());
-                                System.out.println("     resource: " + syncTaskTO.getResource());
-                                System.out.println("     realm destination: " + syncTaskTO.getDestinationRealm());
-                                System.out.println("     cron expression: " + syncTaskTO.getCronExpression());
-                                System.out.println("     description: " + syncTaskTO.getDescription());
-                                System.out.println("     is full reconciliation: "
-                                        + syncTaskTO.isFullReconciliation());
-                                System.out.println("     is perform create: " + syncTaskTO.isPerformCreate());
-                                System.out.println("     is perform delete: " + syncTaskTO.isPerformDelete());
-                                System.out.println("     is perform update: " + syncTaskTO.isPerformUpdate());
-                                System.out.println("     is sync status: " + syncTaskTO.isSyncStatus());
-                                System.out.println("     templates:");
-                                for (Map.Entry<String, AnyTO> entrySet : syncTaskTO.getTemplates().entrySet()) {
-                                    final String key = entrySet.getKey();
-                                    final AnyTO value = entrySet.getValue();
-                                    System.out.println("        " + key + "key : " + value.getKey()
-                                            + " of realm" + value.getRealm()
-                                            + " on resource " + value.getResources());
-
-                                }
-                                System.out.println("     start date: " + syncTaskTO.getStartDate());
-                                System.out.println("     end date: " + syncTaskTO.getEndDate());
-                                System.out.println("     next execution: " + syncTaskTO.getNextExec());
-                                System.out.println("     last execution: " + syncTaskTO.getLastExec());
-                                System.out.println("     latest execution status: "
-                                        + syncTaskTO.getLatestExecStatus());
-                                System.out.println("     job delegate class: "
-                                        + syncTaskTO.getJobDelegateClassName());
-                                System.out.println("     action class name: " + syncTaskTO.getActionsClassNames());
-                                System.out.println("     matching rule: " + syncTaskTO.getMatchingRule());
-                                System.out.println("     unmatching rule: " + syncTaskTO.getUnmatchingRule());
-                                for (final TaskExecTO taskExecTO : syncTaskTO.getExecutions()) {
-                                    printTaskExecTO(taskExecTO);
-                                }
-                                System.out.println("");
-                            }
-                        } catch (final NumberFormatException ex) {
-                            Messages.printIdNotNumberDeletedMessage("task", parameter);
-                        } catch (final SyncopeClientException | WebServiceException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Task", parameter);
-                            } else {
-                                Messages.printMessage("Error: " + ex.getMessage());
-                            }
-                            break;
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(readErrorMessage);
-                }
-                break;
-            case READ_EXECUTION:
-                final String readExecutionErrorMessage = "task --read-execution {TASK-ID} {TASK-ID} [...]";
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            final TaskExecTO taskExecTO = taskService.readExecution(Long.valueOf(parameter));
-                            printTaskExecTO(taskExecTO);
-                        } catch (final NumberFormatException ex) {
-                            Messages.printIdNotNumberDeletedMessage("task execution", parameter);
-                        } catch (final SyncopeClientException | WebServiceException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Task execution", parameter);
-                            } else {
-                                Messages.printMessage("Error: " + ex.getMessage());
-                            }
-                            break;
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(readExecutionErrorMessage);
-                }
-                break;
-            case DELETE:
-                final String deleteErrorMessage = "task --delete {TASK-ID} {TASK-ID} [...]";
-
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            taskService.delete(Long.valueOf(parameter));
-                            Messages.printDeletedMessage("Task", parameter);
-                        } catch (final WebServiceException | SyncopeClientException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Task", parameter);
-                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
-                                Messages.printMessage("You cannot delete task " + parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                        } catch (final NumberFormatException ex) {
-                            Messages.printIdNotNumberDeletedMessage("task", parameter);
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(deleteErrorMessage);
-                }
-                break;
-            case DELETE_EXECUTION:
-                final String deleteExecutionErrorMessage = "task --delete-execution "
-                        + "{TASK-EXEC-ID} {TASK-EXEC-ID} [...]";
-
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            taskService.deleteExecution(Long.valueOf(parameter));
-                            Messages.printDeletedMessage("Task execution", parameter);
-                        } catch (final WebServiceException | SyncopeClientException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Task execution", parameter);
-                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
-                                Messages.printMessage("You cannot delete task execution" + parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                        } catch (final NumberFormatException ex) {
-                            Messages.printIdNotNumberDeletedMessage("task execution", parameter);
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(deleteExecutionErrorMessage);
-                }
-                break;
-            case EXECUTE:
-                final String executeErrorMessage = "task --execute {TASK-ID} {DRY-RUN}\n"
-                        + "          Dry run: true / false";
-
-                if (parameters.length == 2) {
-
-                    try {
-                        final Long taskIdToExecute = Long.valueOf(parameters[0]);
-                        boolean dryRun;
-                        if ("false".equalsIgnoreCase(parameters[1])) {
-                            dryRun = false;
-                        } else if ("true".equalsIgnoreCase(parameters[1])) {
-                            dryRun = true;
-                        } else {
-                            Messages.printNotBooleanDeletedMessage("dry run", parameters[1]);
-                            break;
-                        }
-                        final TaskExecTO taskExecTO = taskService.execute(taskIdToExecute, dryRun);
-                        printTaskExecTO(taskExecTO);
-                    } catch (final WebServiceException | SyncopeClientException ex) {
-                        if (ex.getMessage().startsWith("NotFound")) {
-                            Messages.printNofFoundMessage("Task", parameters[0]);
-                        } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
-                            Messages.printMessage("You cannot delete task " + parameters[0]);
-                        } else {
-                            Messages.printMessage(ex.getMessage());
-                        }
-                    } catch (final NumberFormatException ex) {
-                        Messages.printIdNotNumberDeletedMessage("task", parameters[0]);
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(executeErrorMessage);
-                }
-                break;
-            case HELP:
-                System.out.println(HELP_MESSAGE);
-                break;
-            default:
-                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
-        }
-
-    }
-
-    private void printTaskExecTO(final TaskExecTO taskExecTO) {
-        System.out.println("     EXECUTIONS: ");
-        System.out.println("     - task execution key: " + taskExecTO.getKey());
-        System.out.println("       task: " + taskExecTO.getTask());
-        System.out.println("       message: ");
-        System.out.println("       ###############     <BEGIN MESSAGE>     ###############");
-        System.out.println("       message: " + taskExecTO.getMessage());
-        System.out.println("       ###############     <END   MESSAGE>     ###############");
-        System.out.println("       status: " + taskExecTO.getStatus());
-        System.out.println("       start date: " + taskExecTO.getStartDate());
-        System.out.println("       end date: " + taskExecTO.getEndDate());
-        System.out.println("");
-    }
-
-    @Override
-    public String getHelpMessage() {
-        return HELP_MESSAGE;
-    }
-
-    private enum Options {
-
-        HELP("--help"),
-        LIST_TASK("--list-task"),
-        LIST_RUNNING_JOBS("--list-running-jobs"),
-        LIST_SCHEDULED_JOBS("--list-scheduled-jobs"),
-        READ("--read"),
-        READ_EXECUTION("--read-execution"),
-        DELETE("--delete"),
-        DELETE_EXECUTION("--delete-execution"),
-        EXECUTE("--execute");
-
-        private final String optionName;
-
-        Options(final String optionName) {
-            this.optionName = optionName;
-        }
-
-        public String getOptionName() {
-            return optionName;
-        }
-
-        public boolean equalsOptionName(final String otherName) {
-            return (otherName == null) ? false : optionName.equals(otherName);
-        }
-
-        public static Options fromName(final String name) {
-            Options optionToReturn = HELP;
-            for (final Options option : Options.values()) {
-                if (option.equalsOptionName(name)) {
-                    optionToReturn = option;
-                }
-            }
-            return optionToReturn;
-        }
-
-        public static List<String> toList() {
-            final List<String> options = new ArrayList<>();
-            for (final Options value : values()) {
-                options.add(value.getOptionName());
-            }
-            return options;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/AbstractTaskCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/AbstractTaskCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/AbstractTaskCommand.java
new file mode 100644
index 0000000..18e877a
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/AbstractTaskCommand.java
@@ -0,0 +1,30 @@
+/*
+ * 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.cli.commands.task;
+
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.common.rest.api.service.TaskService;
+
+public abstract class AbstractTaskCommand {
+
+    protected final TaskService taskService = SyncopeServices.get(TaskService.class);
+
+    protected final TaskResultManager taskResultManager = new TaskResultManager();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskCommand.java
new file mode 100644
index 0000000..a616692
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskCommand.java
@@ -0,0 +1,140 @@
+/*
+ * 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.cli.commands.task;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.commands.AbstractCommand;
+
+@Command(name = "task")
+public class TaskCommand extends AbstractCommand {
+
+    private static final String HELP_MESSAGE = "Usage: task [options]\n"
+            + "  Options:\n"
+            + "    --help \n"
+            + "    --list-task \n"
+            + "       Syntax: --list-task {TASK-TYPE} \n"
+            + "          Task type: NOTIFICATION / PROPAGATION / PUSH / SCHEDULED / SYNCHRONIZATION\n"
+            + "    --list-running-jobs \n"
+            + "    --list-scheduled-jobs \n"
+            + "    --read \n"
+            + "       Syntax: --read {TASK-ID} {TASK-ID} [...]\n"
+            + "    --read-execution \n"
+            + "       Syntax: --read-execution {TASK-EXEC-ID} {TASK-EXEC-ID} [...]\n"
+            + "    --delete \n"
+            + "       Syntax: --delete {TASK-ID} {TASK-ID} [...]\n"
+            + "    --delete-execution \n"
+            + "       Syntax: --delete-execution {TASK-EXEC-ID} {TASK-EXEC-ID} [...]\n"
+            + "    --execute \n"
+            + "       Syntax: --execute {TASK-ID} {DRY-RUN}"
+            + "          Dry run: true / false";
+
+    @Override
+    public void execute(final Input input) {
+        if (StringUtils.isBlank(input.getOption())) {
+            input.setOption(Options.HELP.getOptionName());
+        }
+
+        switch (Options.fromName(input.getOption())) {
+            case LIST_TASK:
+                new TaskList(input).list();
+                break;
+            case LIST_RUNNING_JOBS:
+                new TaskRunningJobs().list();
+                break;
+            case LIST_SCHEDULED_JOBS:
+                new TaskScheduledJobs().list();
+                break;
+            case READ:
+                new TaskRead(input).read();
+                break;
+            case READ_EXECUTION:
+                new TaskExecutionRead(input).read();
+                break;
+            case DELETE:
+                new TaskDelete(input).delete();
+                break;
+            case DELETE_EXECUTION:
+                new TaskExecutionDelete(input).delete();
+                break;
+            case EXECUTE:
+                new TaskExecute(input).execute();
+                break;
+            case HELP:
+                System.out.println(HELP_MESSAGE);
+                break;
+            default:
+                new TaskResultManager().defaultError(input.getOption(), HELP_MESSAGE);
+        }
+
+    }
+
+    @Override
+    public String getHelpMessage() {
+        return HELP_MESSAGE;
+    }
+
+    private enum Options {
+
+        HELP("--help"),
+        LIST_TASK("--list-task"),
+        LIST_RUNNING_JOBS("--list-running-jobs"),
+        LIST_SCHEDULED_JOBS("--list-scheduled-jobs"),
+        READ("--read"),
+        READ_EXECUTION("--read-execution"),
+        DELETE("--delete"),
+        DELETE_EXECUTION("--delete-execution"),
+        EXECUTE("--execute");
+
+        private final String optionName;
+
+        Options(final String optionName) {
+            this.optionName = optionName;
+        }
+
+        public String getOptionName() {
+            return optionName;
+        }
+
+        public boolean equalsOptionName(final String otherName) {
+            return (otherName == null) ? false : optionName.equals(otherName);
+        }
+
+        public static Options fromName(final String name) {
+            Options optionToReturn = HELP;
+            for (final Options option : Options.values()) {
+                if (option.equalsOptionName(name)) {
+                    optionToReturn = option;
+                }
+            }
+            return optionToReturn;
+        }
+
+        public static List<String> toList() {
+            final List<String> options = new ArrayList<>();
+            for (final Options value : values()) {
+                options.add(value.getOptionName());
+            }
+            return options;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskDelete.java
new file mode 100644
index 0000000..655e112
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskDelete.java
@@ -0,0 +1,58 @@
+/*
+ * 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.cli.commands.task;
+
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+
+public class TaskDelete extends AbstractTaskCommand {
+
+    private static final String DELETE_HELP_MESSAGE = "task --delete {TASK-ID} {TASK-ID} [...]";
+
+    private final Input input;
+
+    public TaskDelete(final Input input) {
+        this.input = input;
+    }
+
+    public void delete() {
+
+        if (input.parameterNumber() >= 1) {
+            for (final String parameter : input.getParameters()) {
+                try {
+                    taskService.delete(Long.valueOf(parameter));
+                    taskResultManager.deletedMessage("Task", parameter);
+                } catch (final WebServiceException | SyncopeClientException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        taskResultManager.notFoundError("Task", parameter);
+                    } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
+                        taskResultManager.generic("You cannot delete task " + parameter);
+                    } else {
+                        taskResultManager.generic(ex.getMessage());
+                    }
+                } catch (final NumberFormatException ex) {
+                    taskResultManager.notBooleanDeletedError("task", parameter);
+                }
+            }
+        } else {
+            taskResultManager.commandOptionError(DELETE_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecute.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecute.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecute.java
new file mode 100644
index 0000000..9f53ece
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecute.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.cli.commands.task;
+
+import java.util.Arrays;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+
+public class TaskExecute extends AbstractTaskCommand {
+
+    private static final String EXECUTE_HELP_MESSAGE = "task --execute {TASK-ID} {DRY-RUN}\n"
+            + "          Dry run: true / false";
+
+    private final Input input;
+
+    public TaskExecute(final Input input) {
+        this.input = input;
+    }
+
+    public void execute() {
+        if (input.parameterNumber() == 2) {
+            try {
+                final Long taskIdToExecute = Long.valueOf(input.firstParameter());
+                boolean dryRun = true;
+                if ("false".equalsIgnoreCase(input.secondParameter())) {
+                    dryRun = false;
+                } else if ("true".equalsIgnoreCase(input.secondParameter())) {
+                    dryRun = true;
+                } else {
+                    taskResultManager.notBooleanDeletedError("dry run", input.secondParameter());
+                }
+                taskResultManager.printTaskExecTO(Arrays.asList(taskService.execute(taskIdToExecute, dryRun)));
+            } catch (final WebServiceException | SyncopeClientException ex) {
+                if (ex.getMessage().startsWith("NotFound")) {
+                    taskResultManager.notFoundError("Task", input.firstParameter());
+                } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
+                    taskResultManager.generic("You cannot delete task " + input.firstParameter());
+                } else {
+                    taskResultManager.generic(ex.getMessage());
+                }
+            } catch (final NumberFormatException ex) {
+                taskResultManager.notBooleanDeletedError("task", input.firstParameter());
+            }
+        } else {
+            taskResultManager.commandOptionError(EXECUTE_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecutionDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecutionDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecutionDelete.java
new file mode 100644
index 0000000..a107716
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecutionDelete.java
@@ -0,0 +1,58 @@
+/*
+ * 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.cli.commands.task;
+
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+
+public class TaskExecutionDelete extends AbstractTaskCommand {
+
+    private static final String DELETE_HELP_MESSAGE = "task --delete-execution "
+            + "{TASK-EXEC-ID} {TASK-EXEC-ID} [...]";
+
+    private final Input input;
+
+    public TaskExecutionDelete(final Input input) {
+        this.input = input;
+    }
+
+    public void delete() {
+        if (input.parameterNumber() >= 1) {
+            for (final String parameter : input.getParameters()) {
+                try {
+                    taskService.deleteExecution(Long.valueOf(parameter));
+                    taskResultManager.deletedMessage("Task execution", parameter);
+                } catch (final WebServiceException | SyncopeClientException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        taskResultManager.notFoundError("Task execution", parameter);
+                    } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
+                        taskResultManager.generic("You cannot delete task execution" + parameter);
+                    } else {
+                        taskResultManager.generic(ex.getMessage());
+                    }
+                } catch (final NumberFormatException ex) {
+                    taskResultManager.notBooleanDeletedError("task execution", parameter);
+                }
+            }
+        } else {
+            taskResultManager.commandOptionError(DELETE_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecutionRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecutionRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecutionRead.java
new file mode 100644
index 0000000..d24641d
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskExecutionRead.java
@@ -0,0 +1,58 @@
+/*
+ * 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.cli.commands.task;
+
+import java.util.Arrays;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+
+public class TaskExecutionRead extends AbstractTaskCommand {
+
+    private static final String EXECUTION_READ_HELP_MESSAGE = "task --read-execution {TASK-ID} {TASK-ID} [...]";
+
+    private final Input input;
+
+    public TaskExecutionRead(final Input input) {
+        this.input = input;
+    }
+
+    public void read() {
+        if (input.parameterNumber() >= 1) {
+            for (final String parameter : input.getParameters()) {
+                try {
+                    taskResultManager.printTaskExecTO(
+                            Arrays.asList(taskService.readExecution(Long.valueOf(parameter))));
+                } catch (final NumberFormatException ex) {
+                    taskResultManager.notBooleanDeletedError("task execution", parameter);
+                } catch (final SyncopeClientException | WebServiceException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        taskResultManager.notFoundError("Task execution", parameter);
+                    } else {
+                        taskResultManager.generic("Error: " + ex.getMessage());
+                    }
+                    break;
+                }
+            }
+        } else {
+            taskResultManager.commandOptionError(EXECUTION_READ_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskList.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskList.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskList.java
new file mode 100644
index 0000000..203dbcb
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskList.java
@@ -0,0 +1,59 @@
+/*
+ * 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.cli.commands.task;
+
+import java.util.LinkedList;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.util.CommandUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.common.rest.api.beans.TaskQuery;
+
+public class TaskList extends AbstractTaskCommand {
+
+    private static final String LIST_HELP_MESSAGE = "task --list-task {TASK-TYPE}\n"
+            + "   Task type: NOTIFICATION / PROPAGATION / PUSH / SCHEDULED / SYNCHRONIZATION";
+
+    private final Input input;
+
+    public TaskList(final Input input) {
+        this.input = input;
+    }
+
+    public void list() {
+        if (input.parameterNumber() == 1) {
+            try {
+                final TaskType taskType = TaskType.valueOf(input.firstParameter());
+                final LinkedList<AbstractTaskTO> taskTOs = new LinkedList<>();
+                for (final AbstractTaskTO taskTO : taskService.list(taskType, new TaskQuery()).getResult()) {
+                    taskTOs.add(taskTO);
+                }
+                taskResultManager.fromList(taskType, taskTOs);
+            } catch (final SyncopeClientException ex) {
+                taskResultManager.generic(ex.getMessage());
+            } catch (final IllegalArgumentException ex) {
+                taskResultManager.typeNotValidError(
+                        "task", input.firstParameter(), CommandUtils.fromEnumToArray(TaskType.class));
+            }
+        } else {
+            taskResultManager.commandOptionError(LIST_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskRead.java
new file mode 100644
index 0000000..2538254
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskRead.java
@@ -0,0 +1,60 @@
+/*
+ * 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.cli.commands.task;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+
+public class TaskRead extends AbstractTaskCommand {
+
+    private static final String READ_HELP_MESSAGE = "task --read {TASK-ID} {TASK-ID} [...]";
+
+    private final Input input;
+
+    public TaskRead(final Input input) {
+        this.input = input;
+    }
+
+    public void read() {
+        if (input.parameterNumber() >= 1) {
+            final LinkedList<AbstractTaskTO> taskTOs = new LinkedList<>();
+            for (final String parameter : input.getParameters()) {
+                try {
+                    taskTOs.add(taskService.read(Long.valueOf(parameter)));
+                } catch (final NumberFormatException ex) {
+                    taskResultManager.notBooleanDeletedError("task", parameter);
+                } catch (final SyncopeClientException | WebServiceException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        taskResultManager.notFoundError("Task", parameter);
+                    } else {
+                        taskResultManager.generic("Error: " + ex.getMessage());
+                    }
+                    break;
+                }
+            }
+            taskResultManager.fromRead(taskTOs);
+        } else {
+            taskResultManager.commandOptionError(READ_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskResultManager.java
new file mode 100644
index 0000000..6075be7
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskResultManager.java
@@ -0,0 +1,222 @@
+/*
+ * 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.cli.commands.task;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.NotificationTaskTO;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.to.SyncTaskTO;
+import org.apache.syncope.common.lib.to.TaskExecTO;
+import org.apache.syncope.common.lib.types.TaskType;
+
+public class TaskResultManager extends CommonsResultManager {
+
+    public void fromRead(final LinkedList<AbstractTaskTO> taskTOs) {
+        for (final AbstractTaskTO taskTO : taskTOs) {
+            if (taskTO instanceof NotificationTaskTO) {
+                printNotificationTask((NotificationTaskTO) taskTO);
+            } else if (taskTO instanceof PropagationTaskTO) {
+                printPropagationTask((PropagationTaskTO) taskTO);
+            } else if (taskTO instanceof PushTaskTO) {
+                printPushTask((PushTaskTO) taskTO);
+            } else if (taskTO instanceof SchedTaskTO) {
+                printScheduledTask((SchedTaskTO) taskTO);
+            } else if (taskTO instanceof SyncTaskTO) {
+                printSyncTask((SyncTaskTO) taskTO);
+            }
+        }
+    }
+
+    public void fromList(final TaskType taskType, final LinkedList<AbstractTaskTO> taskTOs) {
+        switch (taskType) {
+            case NOTIFICATION:
+                for (final AbstractTaskTO taskTO : taskTOs) {
+                    printNotificationTask(((NotificationTaskTO) taskTO));
+                }
+                break;
+            case PROPAGATION:
+                for (final AbstractTaskTO taskTO : taskTOs) {
+                    printPropagationTask((PropagationTaskTO) taskTO);
+                }
+                break;
+            case PUSH:
+                for (final AbstractTaskTO taskTO : taskTOs) {
+                    printPushTask((PushTaskTO) taskTO);
+                }
+                break;
+            case SCHEDULED:
+                for (final AbstractTaskTO taskTO : taskTOs) {
+                    printScheduledTask((SchedTaskTO) taskTO);
+                }
+                break;
+            case SYNCHRONIZATION:
+                for (final AbstractTaskTO taskTO : taskTOs) {
+                    printSyncTask((SyncTaskTO) taskTO);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    private void printNotificationTask(final NotificationTaskTO notificationTaskTO) {
+        System.out.println("");
+        System.out.println(" - Notification task key: " + notificationTaskTO.getKey());
+        System.out.println("     executed: " + notificationTaskTO.isExecuted());
+        System.out.println("     sender: " + notificationTaskTO.getSender());
+        System.out.println("     subjetc: " + notificationTaskTO.getSubject());
+        System.out.println("     text body: " + notificationTaskTO.getTextBody());
+        System.out.println("     html body: " + notificationTaskTO.getHtmlBody());
+        System.out.println("     latest execution status: "
+                + notificationTaskTO.getLatestExecStatus());
+        System.out.println("     start date: " + notificationTaskTO.getStartDate());
+        System.out.println("     end date: " + notificationTaskTO.getEndDate());
+        System.out.println("     recipients: " + notificationTaskTO.getRecipients());
+        System.out.println("     trace level: " + notificationTaskTO.getTraceLevel());
+        printTaskExecTO(notificationTaskTO.getExecutions());
+        System.out.println("");
+    }
+
+    private void printPropagationTask(final PropagationTaskTO propagationTaskTO) {
+        System.out.println("");
+        System.out.println(" - Propagation task key: " + propagationTaskTO.getKey());
+        System.out.println("     resource: " + propagationTaskTO.getResource());
+        System.out.println("     any key: " + propagationTaskTO.getAnyKey());
+        System.out.println("     any type kind: " + propagationTaskTO.getAnyTypeKind());
+        System.out.println("     connector object key: "
+                + propagationTaskTO.getConnObjectKey());
+        System.out.println("     old connector object key: "
+                + propagationTaskTO.getOldConnObjectKey());
+        System.out.println("     latest execution status: "
+                + propagationTaskTO.getLatestExecStatus());
+        System.out.println("     class name: " + propagationTaskTO.getObjectClassName());
+        System.out.println("     xml attribute: " + propagationTaskTO.getXmlAttributes());
+        System.out.println("     start date: " + propagationTaskTO.getStartDate());
+        System.out.println("     end date: " + propagationTaskTO.getEndDate());
+        System.out.println("     operation: " + propagationTaskTO.getOperation());
+        printTaskExecTO(propagationTaskTO.getExecutions());
+        System.out.println("");
+    }
+
+    private void printPushTask(final PushTaskTO pushTaskTO) {
+        System.out.println("");
+        System.out.println(" - Push task key: " + pushTaskTO.getKey());
+        System.out.println("     name: " + pushTaskTO.getName());
+        System.out.println("     resource: " + pushTaskTO.getResource());
+        System.out.println("     cron expression: " + pushTaskTO.getCronExpression());
+        System.out.println("     description: " + pushTaskTO.getDescription());
+        System.out.println("     is perform create: " + pushTaskTO.isPerformCreate());
+        System.out.println("     is perform delete: " + pushTaskTO.isPerformDelete());
+        System.out.println("     is perform update: " + pushTaskTO.isPerformUpdate());
+        System.out.println("     is sync status: " + pushTaskTO.isSyncStatus());
+        System.out.println("     start date: " + pushTaskTO.getStartDate());
+        System.out.println("     end date: " + pushTaskTO.getEndDate());
+        System.out.println("     last execution: " + pushTaskTO.getLastExec());
+        System.out.println("     next execution: " + pushTaskTO.getNextExec());
+        System.out.println("     latest execution status: "
+                + pushTaskTO.getLatestExecStatus());
+        System.out.println("     filters: " + pushTaskTO.getFilters());
+        System.out.println("     delegate class: " + pushTaskTO.getJobDelegateClassName());
+        System.out.println("     action class: " + pushTaskTO.getActionsClassNames());
+        System.out.println("     matching rule: " + pushTaskTO.getMatchingRule());
+        System.out.println("     not matching rule: " + pushTaskTO.getUnmatchingRule());
+        printTaskExecTO(pushTaskTO.getExecutions());
+
+        System.out.println("");
+    }
+
+    private void printScheduledTask(final SchedTaskTO schedTaskTO) {
+        System.out.println("");
+        System.out.println(" - Scheduled task key: " + schedTaskTO.getKey());
+        System.out.println("     name: " + schedTaskTO.getName());
+        System.out.println("     cron expression: " + schedTaskTO.getCronExpression());
+        System.out.println("     description: " + schedTaskTO.getDescription());
+        System.out.println("     start date: " + schedTaskTO.getStartDate());
+        System.out.println("     end date: " + schedTaskTO.getEndDate());
+        System.out.println("     last execution: " + schedTaskTO.getLastExec());
+        System.out.println("     next execution: " + schedTaskTO.getNextExec());
+        System.out.println("     latest execution status: "
+                + schedTaskTO.getLatestExecStatus());
+        System.out.println("     job delegate class: "
+                + schedTaskTO.getJobDelegateClassName());
+        printTaskExecTO(schedTaskTO.getExecutions());
+        System.out.println("");
+    }
+
+    private void printSyncTask(final SyncTaskTO syncTaskTO) {
+        System.out.println("");
+        System.out.println(" - Sync task key: " + syncTaskTO.getKey());
+        System.out.println("     name: " + syncTaskTO.getName());
+        System.out.println("     resource: " + syncTaskTO.getResource());
+        System.out.println("     realm destination: " + syncTaskTO.getDestinationRealm());
+        System.out.println("     cron expression: " + syncTaskTO.getCronExpression());
+        System.out.println("     description: " + syncTaskTO.getDescription());
+        System.out.println("     is full reconciliation: "
+                + syncTaskTO.isFullReconciliation());
+        System.out.println("     is perform create: " + syncTaskTO.isPerformCreate());
+        System.out.println("     is perform delete: " + syncTaskTO.isPerformDelete());
+        System.out.println("     is perform update: " + syncTaskTO.isPerformUpdate());
+        System.out.println("     is sync status: " + syncTaskTO.isSyncStatus());
+        System.out.println("     templates:");
+        for (Map.Entry<String, AnyTO> entrySet : syncTaskTO.getTemplates().entrySet()) {
+            final String key = entrySet.getKey();
+            final AnyTO value = entrySet.getValue();
+            System.out.println("        " + key + " key: " + value.getKey()
+                    + " of realm" + value.getRealm()
+                    + " on resource " + value.getResources());
+
+        }
+        System.out.println("     start date: " + syncTaskTO.getStartDate());
+        System.out.println("     end date: " + syncTaskTO.getEndDate());
+        System.out.println("     next execution: " + syncTaskTO.getNextExec());
+        System.out.println("     last execution: " + syncTaskTO.getLastExec());
+        System.out.println("     latest execution status: "
+                + syncTaskTO.getLatestExecStatus());
+        System.out.println("     job delegate class: "
+                + syncTaskTO.getJobDelegateClassName());
+        System.out.println("     action class name: " + syncTaskTO.getActionsClassNames());
+        System.out.println("     matching rule: " + syncTaskTO.getMatchingRule());
+        System.out.println("     unmatching rule: " + syncTaskTO.getUnmatchingRule());
+        printTaskExecTO(syncTaskTO.getExecutions());
+        System.out.println("");
+    }
+
+    public void printTaskExecTO(final List<TaskExecTO> taskExecTOs) {
+        for (final TaskExecTO taskExecTO : taskExecTOs) {
+            System.out.println("     EXECUTIONS: ");
+            System.out.println("     - task execution key: " + taskExecTO.getKey());
+            System.out.println("       task: " + taskExecTO.getTask());
+            System.out.println("       message: ");
+            System.out.println("       ###############     <BEGIN MESSAGE>     ###############");
+            System.out.println("       message: " + taskExecTO.getMessage());
+            System.out.println("       ###############     <END   MESSAGE>     ###############");
+            System.out.println("       status: " + taskExecTO.getStatus());
+            System.out.println("       start date: " + taskExecTO.getStartDate());
+            System.out.println("       end date: " + taskExecTO.getEndDate());
+            System.out.println("");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskRunningJobs.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskRunningJobs.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskRunningJobs.java
new file mode 100644
index 0000000..fdb886f
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskRunningJobs.java
@@ -0,0 +1,34 @@
+/*
+ * 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.cli.commands.task;
+
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.types.JobStatusType;
+
+public class TaskRunningJobs extends AbstractTaskCommand {
+
+    public void list() {
+        try {
+            taskResultManager.printTaskExecTO(taskService.listJobs(JobStatusType.RUNNING));
+        } catch (final SyncopeClientException ex) {
+            taskResultManager.generic(ex.getMessage());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/73f73f20/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskScheduledJobs.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskScheduledJobs.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskScheduledJobs.java
new file mode 100644
index 0000000..d95f122
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/task/TaskScheduledJobs.java
@@ -0,0 +1,34 @@
+/*
+ * 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.cli.commands.task;
+
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.types.JobStatusType;
+
+public class TaskScheduledJobs extends AbstractTaskCommand {
+
+    public void list() {
+        try {
+            taskResultManager.printTaskExecTO(taskService.listJobs(JobStatusType.SCHEDULED));
+        } catch (final SyncopeClientException ex) {
+            taskResultManager.generic(ex.getMessage());
+        }
+    }
+
+}


[08/54] [abbrv] syncope git commit: Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/syncope

Posted by fm...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/syncope


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

Branch: refs/heads/SYNCOPE-156
Commit: 36ad4ace07fe03cc8605e1d7e43d2d88bb9d2bc7
Parents: 77c2999 e98d2b2
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 15 12:26:40 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 15 12:26:40 2015 +0200

----------------------------------------------------------------------
 .../apache/syncope/client/cli/SyncopeAdm.java   |   1 +
 .../cli/commands/ConfigurationCommand.java      |  47 +++---
 .../client/cli/commands/DomainCommand.java      | 166 +++++++++++++++++++
 .../client/cli/commands/LoggerCommand.java      |  39 ++---
 .../cli/commands/NotificationCommand.java       |  20 +--
 .../client/cli/commands/PolicyCommand.java      |  29 ++--
 .../client/cli/commands/ReportCommand.java      |  60 +++----
 .../client/cli/commands/SchemaCommand.java      |  28 ++--
 .../syncope/client/cli/messages/Messages.java   |  16 +-
 9 files changed, 274 insertions(+), 132 deletions(-)
----------------------------------------------------------------------



[09/54] [abbrv] syncope git commit: Upgrading Tomcat

Posted by fm...@apache.org.
Upgrading Tomcat


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

Branch: refs/heads/SYNCOPE-156
Commit: 56e05c641cbb4a39eee7c3825bf751d7efa5d070
Parents: 36ad4ac
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 15 14:29:03 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 15 14:29:03 2015 +0200

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/56e05c64/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index f12e9b5..84a791a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -412,7 +412,7 @@ under the License.
     <cargo.log>${log.directory}/cargo.log</cargo.log>
     <cargo.output>${log.directory}/cargo-output.log</cargo.output>
 
-    <tomcat.version>8.0.27</tomcat.version>
+    <tomcat.version>8.0.28</tomcat.version>
 
     <anonymousUser>anonymous</anonymousUser>
     <!-- static keys, only used for build: generated overlays will override during archetype:generate -->


[03/54] [abbrv] syncope git commit: [SYNCOPE-710] Merge from 1_2_X

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateProcessor.java
----------------------------------------------------------------------
diff --cc ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateProcessor.java
index c50240c,0000000..bd0df76
mode 100644,000000..100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateProcessor.java
@@@ -1,88 -1,0 +1,89 @@@
 +/*
 + * 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.provisioning.camel.processor;
 +
 +import java.util.List;
 +import org.apache.camel.Exchange;
 +import org.apache.camel.Processor;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 +import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.stereotype.Component;
 +
 +@Component
 +public class UserUpdateProcessor implements Processor {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(UserUpdateProcessor.class);
 +
 +    @Autowired
 +    protected PropagationManager propagationManager;
 +
 +    @Autowired
 +    protected PropagationTaskExecutor taskExecutor;
 +
 +    @Autowired
 +    protected VirAttrHandler virtAttrHandler;
 +
 +    @Override
 +    @SuppressWarnings("unchecked")
 +    public void process(final Exchange exchange) {
 +        WorkflowResult<Pair<UserPatch, Boolean>> updated = (WorkflowResult) exchange.getIn().getBody();
 +        UserPatch userPatch = exchange.getProperty("actual", UserPatch.class);
 +
-         List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(updated);
-         if (tasks.isEmpty()) {
-             // SYNCOPE-459: take care of user virtual attributes ...
-             PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                     updated.getResult().getKey().getKey(),
-                     AnyTypeKind.USER,
-                     userPatch.getVirAttrs());
-             if (!propByResVirAttr.isEmpty()) {
-                 tasks.addAll(propagationManager.getUserUpdateTasks(updated, false, null));
-             }
++        // SYNCOPE-459: take care of user virtual attributes ...
++        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
++                updated.getResult().getKey().getKey(),
++                AnyTypeKind.USER,
++                userPatch.getVirAttrs());
++        if (updated.getPropByRes() == null) {
++            updated.setPropByRes(propByResVirAttr);
++        } else {
++            updated.getPropByRes().merge(propByResVirAttr);
 +        }
 +
++        List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(updated);
++
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        if (!tasks.isEmpty()) {
 +            try {
 +                taskExecutor.execute(tasks, propagationReporter);
 +            } catch (PropagationException e) {
 +                LOG.error("Error propagation primary resource", e);
 +                propagationReporter.onPrimaryResourceFailure(tasks);
 +            }
 +        }
 +
 +        exchange.getOut().setBody(new ImmutablePair<>(
 +                updated.getResult().getKey().getKey(), propagationReporter.getStatuses()));
 +    }
 +}


[36/54] [abbrv] syncope git commit: refactoring of the domain stack, SYNCOPE-158

Posted by fm...@apache.org.
refactoring of the domain stack, SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 171c0ae360d913c20c846a4a17983e5ca1540002
Parents: dfc1df4
Author: massi <ma...@tirasa.net>
Authored: Wed Oct 21 13:29:56 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Wed Oct 21 13:29:56 2015 +0200

----------------------------------------------------------------------
 .../main/java/org/apache/syncope/client/cli/SyncopeAdm.java  | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/171c0ae3/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
index ea11a22..7308c57 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
@@ -28,7 +28,7 @@ public final class SyncopeAdm {
 
     private static final Logger LOG = LoggerFactory.getLogger(SyncopeAdm.class);
     
-    private static final ResultManager resultManager = new ResultManager();
+    private static final ResultManager RESULT_MANAGER = new ResultManager();
 
     public static void main(final String[] args) {
         LOG.debug("Starting with args \n");
@@ -50,12 +50,12 @@ public final class SyncopeAdm {
             System.out.println(helpMessage());
         } catch (final IllegalArgumentException ex) {
             LOG.error("Error in main", ex);
-            resultManager.generic(ex.getMessage());
+            RESULT_MANAGER.generic(ex.getMessage());
             if (!ex.getMessage().startsWith("It seems you")) {
                 System.out.println(helpMessage());
             }
         } catch (final ProcessingException e) {
-            resultManager.generic("Syncope server offline", e.getCause().getMessage());
+            RESULT_MANAGER.generic("Syncope server offline", e.getCause().getMessage());
         }
 
     }
@@ -73,7 +73,7 @@ public final class SyncopeAdm {
                 helpMessageBuilder.append("\n");
             }
         } catch (final IllegalAccessException | IllegalArgumentException | InstantiationException ex) {
-            resultManager.generic(ex.getMessage());
+            RESULT_MANAGER.generic(ex.getMessage());
         }
 
         return helpMessageBuilder.toString();


[28/54] [abbrv] syncope git commit: checkstyle plugin told me to delete a private modifier

Posted by fm...@apache.org.
checkstyle plugin told me to delete a private modifier


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

Branch: refs/heads/SYNCOPE-156
Commit: 85d4e836cecd4c828c3b965afb5af32c933a90fb
Parents: 758a3c4
Author: massi <ma...@tirasa.net>
Authored: Tue Oct 20 15:02:23 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Tue Oct 20 15:02:23 2015 +0200

----------------------------------------------------------------------
 .../apache/syncope/client/cli/commands/logger/LoggerCommand.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/85d4e836/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
index 1199218..399723b 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
@@ -94,7 +94,7 @@ public class LoggerCommand extends AbstractCommand {
 
         private final String optionName;
 
-        private LoggerOptions(final String optionName) {
+        private static LoggerOptions(final String optionName) {
             this.optionName = optionName;
         }
 


[35/54] [abbrv] syncope git commit: refactoring of the domain stack, SYNCOPE-158

Posted by fm...@apache.org.
refactoring of the domain stack, SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: dfc1df48398e9b1421d23c1fb2ab8c3c6cb03ad8
Parents: 469b749
Author: massi <ma...@tirasa.net>
Authored: Wed Oct 21 13:28:46 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Wed Oct 21 13:28:46 2015 +0200

----------------------------------------------------------------------
 .../syncope/client/cli/ResultManager.java       |  25 +++
 .../apache/syncope/client/cli/SyncopeAdm.java   |   9 +-
 .../cli/commands/CommonsResultManager.java      |   2 +-
 .../client/cli/commands/DomainCommand.java      | 165 -------------------
 .../cli/commands/NotificationCommand.java       |   2 +-
 .../client/cli/commands/PolicyCommand.java      |   2 +-
 .../client/cli/commands/ReportCommand.java      |   2 +-
 .../client/cli/commands/SchemaCommand.java      |   1 -
 .../client/cli/commands/TaskCommand.java        |   2 +-
 .../configuration/ConfigurationCommand.java     |   4 -
 .../configuration/ConfigurationDelete.java      |   4 +-
 .../configuration/ConfigurationExport.java      |  12 +-
 .../configuration/ConfigurationGet.java         |   2 +-
 .../configuration/ConfigurationRead.java        |   2 +-
 .../configuration/ConfigurationUpdate.java      |   6 +-
 .../commands/domain/AbstractDomainCommand.java  |  30 ++++
 .../cli/commands/domain/DomainCommand.java      | 101 ++++++++++++
 .../cli/commands/domain/DomainDelete.java       |  53 ++++++
 .../client/cli/commands/domain/DomainList.java  |  38 +++++
 .../client/cli/commands/domain/DomainRead.java  |  53 ++++++
 .../commands/domain/DomainResultManager.java    |  25 +++
 .../cli/commands/install/InstallCommand.java    |   5 -
 .../cli/commands/install/InstallSetup.java      |   3 +
 .../cli/commands/logger/LoggerDelete.java       |   2 +-
 .../client/cli/commands/logger/LoggerList.java  |   2 +-
 .../client/cli/commands/logger/LoggerRead.java  |   2 +-
 .../cli/commands/logger/LoggerUpdate.java       |   4 +-
 .../cli/commands/logger/LoggerUpdateAll.java    |   2 +-
 28 files changed, 357 insertions(+), 203 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/ResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/ResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/ResultManager.java
new file mode 100644
index 0000000..de3d0f1
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/ResultManager.java
@@ -0,0 +1,25 @@
+/*
+ * 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.cli;
+
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+
+public class ResultManager extends CommonsResultManager {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
index b5a1365..ea11a22 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
@@ -20,7 +20,6 @@ package org.apache.syncope.client.cli;
 
 import javax.ws.rs.ProcessingException;
 import org.apache.syncope.client.cli.commands.AbstractCommand;
-import org.apache.syncope.client.cli.commands.logger.LoggerResultManager;
 import org.apache.syncope.client.cli.util.CommandUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -28,6 +27,8 @@ import org.slf4j.LoggerFactory;
 public final class SyncopeAdm {
 
     private static final Logger LOG = LoggerFactory.getLogger(SyncopeAdm.class);
+    
+    private static final ResultManager resultManager = new ResultManager();
 
     public static void main(final String[] args) {
         LOG.debug("Starting with args \n");
@@ -49,12 +50,12 @@ public final class SyncopeAdm {
             System.out.println(helpMessage());
         } catch (final IllegalArgumentException ex) {
             LOG.error("Error in main", ex);
-            new LoggerResultManager().genericError(ex.getMessage());
+            resultManager.generic(ex.getMessage());
             if (!ex.getMessage().startsWith("It seems you")) {
                 System.out.println(helpMessage());
             }
         } catch (final ProcessingException e) {
-            new LoggerResultManager().genericError("Syncope server offline", e.getCause().getMessage());
+            resultManager.generic("Syncope server offline", e.getCause().getMessage());
         }
 
     }
@@ -72,7 +73,7 @@ public final class SyncopeAdm {
                 helpMessageBuilder.append("\n");
             }
         } catch (final IllegalAccessException | IllegalArgumentException | InstantiationException ex) {
-            new LoggerResultManager().genericError(ex.getMessage());
+            resultManager.generic(ex.getMessage());
         }
 
         return helpMessageBuilder.toString();

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
index 9bfde8d..255b99b 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
@@ -44,7 +44,7 @@ public abstract class CommonsResultManager {
         Messages.printDefaultMessage(option, helpMessage);
     }
 
-    public void genericError(final String... messages) {
+    public void generic(final String... messages) {
         Messages.printMessage(messages);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
deleted file mode 100644
index 8d4cfdf..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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.cli.commands;
-
-import org.apache.syncope.client.cli.commands.logger.LoggerCommand;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.cli.Command;
-import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.SyncopeServices;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.DomainTO;
-import org.apache.syncope.common.rest.api.service.DomainService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Command(name = "domain")
-public class DomainCommand extends AbstractCommand {
-
-    private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
-
-    private static final String HELP_MESSAGE = "Usage: domain [options]\n"
-            + "  Options:\n"
-            + "    --help \n"
-            + "    --list \n"
-            + "    --read \n"
-            + "       Syntax: --read {DOMAIN-KEY} {DOMAIN-KEY} [...]\n"
-            + "    --delete \n"
-            + "       Syntax: --delete {DOMAIN-KEY} {DOMAIN-KEY} [...]\n";
-
-    @Override
-    public void execute(final Input input) {
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
-        final String[] parameters = input.getParameters();
-
-        if (StringUtils.isBlank(input.getOption())) {
-            input.setOption(Options.HELP.getOptionName());
-        }
-
-        final DomainService domainService = SyncopeServices.get(DomainService.class);
-        switch (Options.fromName(input.getOption())) {
-            case LIST:
-                try {
-                    for (final DomainTO domainTO : domainService.list()) {
-                        Messages.printMessage("Domain key: " + domainTO.getKey());
-                    }
-                } catch (final SyncopeClientException ex) {
-                    Messages.printMessage("Error: " + ex.getMessage());
-                }
-                break;
-            case READ:
-                final String readErrorMessage = "domain --read {DOMAIN-KEY} {DOMAIN-KEY} [...]";
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            final DomainTO domainTO = domainService.read(parameter);
-                            Messages.printMessage("Domain key: " + domainTO.getKey());
-                        } catch (final SyncopeClientException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Domain", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(readErrorMessage);
-                }
-                break;
-            case DELETE:
-                final String deleteErrorMessage = "domain --delete {DOMAIN-KEY} {DOMAIN-KEY} [...]";
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            domainService.delete(parameter);
-                            Messages.printDeletedMessage("Domain", parameter);
-                        } catch (final SyncopeClientException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Domain", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(deleteErrorMessage);
-                }
-                break;
-            case HELP:
-                System.out.println(HELP_MESSAGE);
-                break;
-            default:
-                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
-        }
-
-    }
-
-    @Override
-    public String getHelpMessage() {
-        return HELP_MESSAGE;
-    }
-
-    private enum Options {
-
-        HELP("--help"),
-        LIST("--list"),
-        READ("--read"),
-        DELETE("--delete");
-
-        private final String optionName;
-
-        Options(final String optionName) {
-            this.optionName = optionName;
-        }
-
-        public String getOptionName() {
-            return optionName;
-        }
-
-        public boolean equalsOptionName(final String otherName) {
-            return (otherName == null) ? false : optionName.equals(otherName);
-        }
-
-        public static Options fromName(final String name) {
-            Options optionToReturn = HELP;
-            for (final Options option : Options.values()) {
-                if (option.equalsOptionName(name)) {
-                    optionToReturn = option;
-                }
-            }
-            return optionToReturn;
-        }
-
-        public static List<String> toList() {
-            final List<String> options = new ArrayList<>();
-            for (final Options value : values()) {
-                options.add(value.getOptionName());
-            }
-            return options;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
index 28ae8c5..3d1866b 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
@@ -45,7 +45,7 @@ public class NotificationCommand extends AbstractCommand {
             + "       Syntax: --read {NOTIFICATION-ID} \n"
             + "    --delete \n"
             + "       Syntax: --delete {NOTIFICATION-ID}";
-
+    
     @Override
     public void execute(final Input input) {
         LOG.debug("Option: {}", input.getOption());

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
index 689b304..fc3a8c0 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
@@ -49,7 +49,7 @@ public class PolicyCommand extends AbstractCommand {
             + "       Syntax: --read {POLICY-ID} {POLICY-ID} [...]\n"
             + "    --delete \n"
             + "       Syntax: --delete {POLICY-ID} {POLICY-ID} [...]";
-
+    
     @Override
     public void execute(final Input input) {
         LOG.debug("Option: {}", input.getOption());

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
index 40ecd54..30be7fb 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
@@ -66,7 +66,7 @@ public class ReportCommand extends AbstractCommand {
             + "       Syntax: --export-execution-result {EXECUTION-ID} {EXECUTION-ID} [...] {FORMAT}\n"
             + "          Format: CSV / HTML / PDF / XML / RTF"
             + "    --reportlet-class";
-
+    
     @Override
     public void execute(final Input input) {
         LOG.debug("Option: {}", input.getOption());

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
index 6838d0a..e00ae3f 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
@@ -56,7 +56,6 @@ public class SchemaCommand extends AbstractCommand {
             + "        Schema type: PLAIN / DERIVED / VIRTUAL";
 
     @Override
-
     public void execute(final Input input) {
         LOG.debug("Option: {}", input.getOption());
         LOG.debug("Parameters:");

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
index 3b50b15..deb00bf 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
@@ -69,7 +69,7 @@ public class TaskCommand extends AbstractCommand {
             + "    --execute \n"
             + "       Syntax: --execute {TASK-ID} {DRY-RUN}"
             + "          Dry run: true / false";
-
+    
     @Override
     public void execute(final Input input) {
         LOG.debug("Option: {}", input.getOption());

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationCommand.java
index d74ea78..00fe6fa 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationCommand.java
@@ -24,14 +24,10 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.client.cli.commands.AbstractCommand;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @Command(name = "configuration")
 public class ConfigurationCommand extends AbstractCommand {
 
-    private static final Logger LOG = LoggerFactory.getLogger(ConfigurationCommand.class);
-
     private static final String HELP_MESSAGE = "Usage: configuration [options]\n"
             + "  Options:\n"
             + "    --help \n"

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationDelete.java
index 4f8c227..f308aa9 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationDelete.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationDelete.java
@@ -42,9 +42,9 @@ public class ConfigurationDelete extends AbstractConfigurationCommand {
                     if (ex.getMessage().startsWith("NotFound")) {
                         configurationResultManager.notFoundError("Configuration", parameter);
                     } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
-                        configurationResultManager.genericError("You cannot delete configuration", parameter);
+                        configurationResultManager.generic("You cannot delete configuration", parameter);
                     } else {
-                        configurationResultManager.genericError(ex.getMessage());
+                        configurationResultManager.generic(ex.getMessage());
                     }
                     break;
                 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationExport.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationExport.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationExport.java
index 0bc274f..2e61c4f 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationExport.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationExport.java
@@ -47,22 +47,22 @@ public class ConfigurationExport extends AbstractConfigurationCommand {
                 XMLUtils.createXMLFile(
                         (SequenceInputStream) configurationService.export().getEntity(),
                         input.firstParameter() + EXPORT_FILE_NAME);
-                configurationResultManager.genericError(
+                configurationResultManager.generic(
                         input.firstParameter() + EXPORT_FILE_NAME + " successfully created");
             } catch (final IOException ex) {
-                configurationResultManager.genericError(ex.getMessage());
+                configurationResultManager.generic(ex.getMessage());
             } catch (ParserConfigurationException | SAXException | TransformerConfigurationException ex) {
-                configurationResultManager.genericError(
+                configurationResultManager.generic(
                         "Error creating " + input.firstParameter() + EXPORT_FILE_NAME + " " + ex.getMessage());
             } catch (final TransformerException ex) {
                 if (ex.getCause() instanceof FileNotFoundException) {
-                    configurationResultManager.genericError("Permission denied on " + input.firstParameter());
+                    configurationResultManager.generic("Permission denied on " + input.firstParameter());
                 } else {
-                    configurationResultManager.genericError(
+                    configurationResultManager.generic(
                             "Error creating " + input.firstParameter() + EXPORT_FILE_NAME + " " + ex.getMessage());
                 }
             } catch (final SyncopeClientException ex) {
-                configurationResultManager.genericError("Error calling configuration service " + ex.getMessage());
+                configurationResultManager.generic("Error calling configuration service " + ex.getMessage());
             }
         } else {
             configurationResultManager.commandOptionError(EXPORT_HELP_MESSAGE);

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
index 472e40f..2aa3ff4 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
@@ -29,7 +29,7 @@ public class ConfigurationGet extends AbstractConfigurationCommand {
         try {
             configurationResultManager.fromGet(new LinkedList<>(configurationService.list()));
         } catch (final Exception ex) {
-            configurationResultManager.genericError(ex.getMessage());
+            configurationResultManager.generic(ex.getMessage());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationRead.java
index 801f01d..c4294e7 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationRead.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationRead.java
@@ -45,7 +45,7 @@ public class ConfigurationRead extends AbstractConfigurationCommand {
                     if (ex.getMessage().startsWith("NotFound")) {
                         configurationResultManager.notFoundError("Configuration", parameter);
                     } else {
-                        configurationResultManager.genericError(ex.getMessage());
+                        configurationResultManager.generic(ex.getMessage());
                     }
                     failed = true;
                     break;

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationUpdate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationUpdate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationUpdate.java
index 9be74e2..295ebd1 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationUpdate.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationUpdate.java
@@ -50,17 +50,17 @@ public class ConfigurationUpdate extends AbstractConfigurationCommand {
                     configurationService.set(attrTO);
                     attrList.add(attrTO);
                 } catch (final IllegalArgumentException ex) {
-                    configurationResultManager.genericError(ex.getMessage(), UPDATE_HELP_MESSAGE);
+                    configurationResultManager.generic(ex.getMessage(), UPDATE_HELP_MESSAGE);
                     failed = true;
                     break;
                 } catch (final SyncopeClientException | WebServiceException ex) {
                     if (ex.getMessage().startsWith("NotFound")) {
                         configurationResultManager.notFoundError("Configuration", pairParameter.getKey());
                     } else if (ex.getMessage().startsWith("InvalidValues")) {
-                        configurationResultManager.genericError(
+                        configurationResultManager.generic(
                                 pairParameter.getValue() + " is not a valid value for " + pairParameter.getKey());
                     } else {
-                        configurationResultManager.genericError(ex.getMessage());
+                        configurationResultManager.generic(ex.getMessage());
                     }
                     failed = true;
                     break;

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/AbstractDomainCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/AbstractDomainCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/AbstractDomainCommand.java
new file mode 100644
index 0000000..8650ef7
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/AbstractDomainCommand.java
@@ -0,0 +1,30 @@
+/*
+ * 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.cli.commands.domain;
+
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.common.rest.api.service.DomainService;
+
+public class AbstractDomainCommand {
+
+    protected final DomainService domainService = SyncopeServices.get(DomainService.class);
+
+    protected final DomainResultManager domainResultManager = new DomainResultManager();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainCommand.java
new file mode 100644
index 0000000..e709b81
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainCommand.java
@@ -0,0 +1,101 @@
+/*
+ * 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.cli.commands.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.commands.AbstractCommand;
+
+@Command(name = "domain")
+public class DomainCommand extends AbstractCommand {
+
+    private static final String HELP_MESSAGE = "Usage: domain [options]\n"
+            + "  Options:\n"
+            + "    --help \n"
+            + "    --list \n"
+            + "    --delete \n"
+            + "       Syntax: --delete {DOMAIN-KEY} {DOMAIN-KEY} [...]\n";
+
+    @Override
+    public void execute(final Input input) {
+        if (StringUtils.isBlank(input.getOption())) {
+            input.setOption(Options.HELP.getOptionName());
+        }
+        switch (Options.fromName(input.getOption())) {
+            case LIST:
+                new DomainList().list();
+                break;
+            case DELETE:
+                new DomainDelete(input).delete();
+                break;
+            case HELP:
+                System.out.println(HELP_MESSAGE);
+                break;
+            default:
+                new DomainResultManager().deletedMessage(input.getOption(), HELP_MESSAGE);
+        }
+    }
+
+    @Override
+    public String getHelpMessage() {
+        return HELP_MESSAGE;
+    }
+
+    private enum Options {
+
+        HELP("--help"),
+        LIST("--list"),
+        DELETE("--delete");
+
+        private final String optionName;
+
+        Options(final String optionName) {
+            this.optionName = optionName;
+        }
+
+        public String getOptionName() {
+            return optionName;
+        }
+
+        public boolean equalsOptionName(final String otherName) {
+            return (otherName == null) ? false : optionName.equals(otherName);
+        }
+
+        public static Options fromName(final String name) {
+            Options optionToReturn = HELP;
+            for (final Options option : Options.values()) {
+                if (option.equalsOptionName(name)) {
+                    optionToReturn = option;
+                }
+            }
+            return optionToReturn;
+        }
+
+        public static List<String> toList() {
+            final List<String> options = new ArrayList<>();
+            for (final Options value : values()) {
+                options.add(value.getOptionName());
+            }
+            return options;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainDelete.java
new file mode 100644
index 0000000..1b0c235
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainDelete.java
@@ -0,0 +1,53 @@
+/*
+ * 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.cli.commands.domain;
+
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+
+public class DomainDelete extends AbstractDomainCommand {
+
+    private static final String DELETE_HELP_MESSAGE = "domain --delete {DOMAIN-KEY} {DOMAIN-KEY} [...]";
+
+    private final Input input;
+
+    public DomainDelete(final Input input) {
+        this.input = input;
+    }
+
+    public void delete() {
+        if (input.parameterNumber() >= 1) {
+            for (final String parameter : input.getParameters()) {
+                try {
+                    domainService.delete(parameter);
+                    domainResultManager.deletedMessage("Domain", parameter);
+                } catch (final SyncopeClientException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        domainResultManager.notFoundError("Domain", parameter);
+                    } else {
+                        domainResultManager.generic(ex.getMessage());
+                    }
+                }
+            }
+        } else {
+            domainResultManager.commandOptionError(DELETE_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainList.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainList.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainList.java
new file mode 100644
index 0000000..94329d2
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainList.java
@@ -0,0 +1,38 @@
+/*
+ * 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.cli.commands.domain;
+
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.DomainTO;
+
+public class DomainList extends AbstractDomainCommand {
+
+    public DomainList() {
+    }
+
+    public void list() {
+        try {
+            for (final DomainTO domainTO : domainService.list()) {
+                domainResultManager.generic(domainTO.getKey());
+            }
+        } catch (final SyncopeClientException ex) {
+            domainResultManager.generic("Error: " + ex.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainRead.java
new file mode 100644
index 0000000..a76711d
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainRead.java
@@ -0,0 +1,53 @@
+/*
+ * 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.cli.commands.domain;
+
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.DomainTO;
+
+public class DomainRead extends AbstractDomainCommand {
+
+    private static final String READ_HELP_MESSAGE = "domain --read {DOMAIN-KEY} {DOMAIN-KEY} [...]";
+
+    private final Input input;
+
+    public DomainRead(final Input input) {
+        this.input = input;
+    }
+
+    public void read() {
+        if (input.parameterNumber() >= 1) {
+            for (final String parameter : input.getParameters()) {
+                try {
+                    final DomainTO domainTO = domainService.read(parameter);
+                    domainResultManager.generic(domainTO.getKey());
+                } catch (final SyncopeClientException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        domainResultManager.notFoundError("Domain", parameter);
+                    } else {
+                        domainResultManager.generic(ex.getMessage());
+                    }
+                }
+            }
+        } else {
+            domainResultManager.commandOptionError(READ_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainResultManager.java
new file mode 100644
index 0000000..6066c5d
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/DomainResultManager.java
@@ -0,0 +1,25 @@
+/*
+ * 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.cli.commands.domain;
+
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+
+public class DomainResultManager extends CommonsResultManager {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
index 0caba9f..7ebd554 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
@@ -22,15 +22,10 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.client.cli.commands.AbstractCommand;
-import org.apache.syncope.client.cli.commands.logger.LoggerCommand;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @Command(name = "install")
 public class InstallCommand extends AbstractCommand {
 
-    private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
-
     private static final String HELP_MESSAGE = "Usage: install [options]\n"
             + "  Options:\n"
             + "    --help \n"

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
index 1486b48..10995b0 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
@@ -44,6 +44,9 @@ public class InstallSetup {
 
     private String syncopeServerRestContext = "/syncope/rest/";
 
+    public InstallSetup() {
+    }
+
     public void setup() {
         final Scanner scanIn = new Scanner(System.in);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
index 6614f07..5815b71 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
@@ -43,7 +43,7 @@ public class LoggerDelete extends AbstractLoggerCommand {
                     if (ex.getMessage().startsWith("NotFound")) {
                         loggerResultManager.notFoundError("Logger", parameter);
                     } else {
-                        loggerResultManager.genericError(ex.getMessage());
+                        loggerResultManager.generic(ex.getMessage());
                     }
                 }
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
index f65da34..d9d4f81 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
@@ -31,7 +31,7 @@ public class LoggerList extends AbstractLoggerCommand {
         try {
             loggerResultManager.fromList(new LinkedList<>(loggerService.list(LoggerType.LOG)));
         } catch (final SyncopeClientException ex) {
-            loggerResultManager.genericError("Error: " + ex.getMessage());
+            loggerResultManager.generic("Error: " + ex.getMessage());
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
index c796c47..6e2447d 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
@@ -46,7 +46,7 @@ public class LoggerRead extends AbstractLoggerCommand {
                     if (ex.getMessage().startsWith("NotFound")) {
                         loggerResultManager.notFoundError("Logger", parameter);
                     } else {
-                        loggerResultManager.genericError("Error: " + ex.getMessage());
+                        loggerResultManager.generic("Error: " + ex.getMessage());
                     }
                     failed = true;
                     break;

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
index cbfc196..7279b96 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
@@ -54,11 +54,11 @@ public class LoggerUpdate extends AbstractLoggerCommand {
                     if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
                         loggerResultManager.typeNotValidError(input.firstParameter());
                     } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
-                        loggerResultManager.genericError(ex.getMessage(), UPDATE_HELP_MESSAGE);
+                        loggerResultManager.generic(ex.getMessage(), UPDATE_HELP_MESSAGE);
                     } else if (ex.getMessage().startsWith("NotFound")) {
                         loggerResultManager.notFoundError("Logger", parameter);
                     } else {
-                        loggerResultManager.genericError(ex.getMessage(), UPDATE_HELP_MESSAGE);
+                        loggerResultManager.generic(ex.getMessage(), UPDATE_HELP_MESSAGE);
                     }
                     failed = true;
                     break;

http://git-wip-us.apache.org/repos/asf/syncope/blob/dfc1df48/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
index 305fa30..f1c25c2 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
@@ -49,7 +49,7 @@ public class LoggerUpdateAll extends AbstractLoggerCommand {
                     if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
                         loggerResultManager.typeNotValidError(input.firstParameter());
                     } else {
-                        loggerResultManager.genericError(ex.getMessage(), UPDATE_ALL_HELP_MESSAGE);
+                        loggerResultManager.generic(ex.getMessage(), UPDATE_ALL_HELP_MESSAGE);
                     }
                     failed = true;
                     break;


[31/54] [abbrv] syncope git commit: refactoring for configuration stack, SYNCOPE-158

Posted by fm...@apache.org.
refactoring for configuration stack, SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 6b9cd592b21440d54fabd6012616c4f6a18a81f3
Parents: 462289d
Author: massi <ma...@tirasa.net>
Authored: Wed Oct 21 10:54:47 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Wed Oct 21 10:54:47 2015 +0200

----------------------------------------------------------------------
 .../apache/syncope/client/cli/SyncopeAdm.java   |   8 +-
 .../cli/commands/CommonsResultManager.java      |  50 ++++
 .../cli/commands/ConfigurationCommand.java      | 297 -------------------
 .../AbstractConfigurationCommand.java           |  30 ++
 .../configuration/ConfigurationCommand.java     | 124 ++++++++
 .../configuration/ConfigurationDelete.java      |  57 ++++
 .../configuration/ConfigurationExport.java      |  71 +++++
 .../configuration/ConfigurationGet.java         |  36 +++
 .../configuration/ConfigurationRead.java        |  62 ++++
 .../ConfigurationResultManager.java             |  53 ++++
 .../configuration/ConfigurationUpdate.java      |  76 +++++
 .../commands/logger/AbstractLoggerCommand.java  |   2 +-
 .../cli/commands/logger/LoggerCommand.java      |   3 +-
 .../cli/commands/logger/LoggerCreate.java       |   6 +-
 .../cli/commands/logger/LoggerDelete.java       |  15 +-
 .../client/cli/commands/logger/LoggerList.java  |   4 +-
 .../client/cli/commands/logger/LoggerRead.java  |   8 +-
 .../commands/logger/LoggerResultManager.java    |  61 ++++
 .../cli/commands/logger/LoggerUpdate.java       |  12 +-
 .../cli/commands/logger/LoggerUpdateAll.java    |   8 +-
 .../cli/commands/logger/ResultManager.java      |  79 -----
 21 files changed, 649 insertions(+), 413 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
index 78e2f54..b5a1365 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
@@ -20,7 +20,7 @@ package org.apache.syncope.client.cli;
 
 import javax.ws.rs.ProcessingException;
 import org.apache.syncope.client.cli.commands.AbstractCommand;
-import org.apache.syncope.client.cli.commands.logger.ResultManager;
+import org.apache.syncope.client.cli.commands.logger.LoggerResultManager;
 import org.apache.syncope.client.cli.util.CommandUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,12 +49,12 @@ public final class SyncopeAdm {
             System.out.println(helpMessage());
         } catch (final IllegalArgumentException ex) {
             LOG.error("Error in main", ex);
-            new ResultManager().genericError(ex.getMessage());
+            new LoggerResultManager().genericError(ex.getMessage());
             if (!ex.getMessage().startsWith("It seems you")) {
                 System.out.println(helpMessage());
             }
         } catch (final ProcessingException e) {
-            new ResultManager().genericError("Syncope server offline", e.getCause().getMessage());
+            new LoggerResultManager().genericError("Syncope server offline", e.getCause().getMessage());
         }
 
     }
@@ -72,7 +72,7 @@ public final class SyncopeAdm {
                 helpMessageBuilder.append("\n");
             }
         } catch (final IllegalAccessException | IllegalArgumentException | InstantiationException ex) {
-            new ResultManager().genericError(ex.getMessage());
+            new LoggerResultManager().genericError(ex.getMessage());
         }
 
         return helpMessageBuilder.toString();

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
new file mode 100644
index 0000000..9bfde8d
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
@@ -0,0 +1,50 @@
+/*
+ * 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.cli.commands;
+
+import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.util.CommandUtils;
+import org.apache.syncope.common.lib.types.LoggerLevel;
+
+public abstract class CommonsResultManager {
+
+    public void deletedMessage(final String what, final String key) {
+        Messages.printDeletedMessage(what, key);
+    }
+
+    public void notFoundError(final String what, final String parameter) {
+        Messages.printNofFoundMessage(what, parameter);
+    }
+
+    public void typeNotValidError(final String parameter) {
+        Messages.printTypeNotValidMessage("logger level", parameter, CommandUtils.fromEnumToArray(LoggerLevel.class));
+    }
+
+    public void commandOptionError(final String message) {
+        Messages.printCommandOptionMessage(message);
+    }
+
+    public void defaultError(final String option, final String helpMessage) {
+        Messages.printDefaultMessage(option, helpMessage);
+    }
+
+    public void genericError(final String... messages) {
+        Messages.printMessage(messages);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
deleted file mode 100644
index e7d8938..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * 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.cli.commands;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.SequenceInputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.ws.WebServiceException;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.cli.Command;
-import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.SyncopeServices;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.messages.TwoColumnTable;
-import org.apache.syncope.client.cli.util.XMLUtils;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.to.ConfTO;
-import org.apache.syncope.common.rest.api.service.ConfigurationService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xml.sax.SAXException;
-
-@Command(name = "configuration")
-public class ConfigurationCommand extends AbstractCommand {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ConfigurationCommand.class);
-
-    private static final String EXPORT_FILE_NAME = "/content.xml";
-
-    private static final String HELP_MESSAGE = "Usage: configuration [options]\n"
-            + "  Options:\n"
-            + "    --help \n"
-            + "    --get \n"
-            + "    --read \n"
-            + "       Syntax: --read {CONF-NAME} {CONF-NAME} [...] \n"
-            + "    --update \n"
-            + "       Syntax: --update {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]\n"
-            + "    --delete \n"
-            + "       Syntax: --delete {CONF-NAME} {CONF-NAME} [...]\n"
-            + "    --export \n"
-            + "       Syntax: --export {WHERE-DIR}";
-
-    @Override
-    public void execute(final Input input) {
-        LOG.debug("Logger service successfully created");
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
-        final String[] parameters = input.getParameters();
-
-        if (StringUtils.isBlank(input.getOption())) {
-            input.setOption(Options.HELP.getOptionName());
-        }
-
-        final ConfigurationService configurationService = SyncopeServices.get(ConfigurationService.class);
-        switch (Options.fromName(input.getOption())) {
-            case GET:
-                try {
-                    final ConfTO confTO = configurationService.list();
-                    toTable("Syncope configuration", "attribute", "value", confTO.getPlainAttrs());
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case READ:
-                final String readErrorMessage = "configuration --read {CONF-NAME} {CONF-NAME} [...]";
-                if (parameters.length >= 1) {
-                    final Set<AttrTO> attrList = new HashSet<>();
-                    boolean failed = false;
-                    for (final String parameter : parameters) {
-                        try {
-                            attrList.add(configurationService.get(parameter));
-                        } catch (final SyncopeClientException | WebServiceException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Logger", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                            failed = true;
-                            break;
-                        }
-                    }
-                    if (!failed) {
-                        toTable("Read result", "attribute", "value", attrList);
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(readErrorMessage);
-                }
-                break;
-            case UPDATE:
-                final String updateErrorMessage
-                        = "configuration --update {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]";
-                if (parameters.length >= 1) {
-                    Input.PairParameter pairParameter = null;
-                    AttrTO attrTO;
-                    final Set<AttrTO> attrList = new HashSet<>();
-                    boolean failed = false;
-                    for (final String parameter : parameters) {
-                        try {
-                            pairParameter = input.toPairParameter(parameter);
-                            attrTO = configurationService.get(pairParameter.getKey());
-                            attrTO.getValues().clear();
-                            attrTO.getValues().add(pairParameter.getValue());
-                            configurationService.set(attrTO);
-                            attrList.add(attrTO);
-                        } catch (final IllegalArgumentException ex) {
-                            Messages.printMessage(ex.getMessage(), updateErrorMessage);
-                            failed = true;
-                            break;
-                        } catch (final SyncopeClientException | WebServiceException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Configuration", pairParameter.getKey());
-                            } else if (ex.getMessage().startsWith("InvalidValues")) {
-                                Messages.printMessage(
-                                        pairParameter.getValue() + " is not a valid value for "
-                                        + pairParameter.getKey());
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                            failed = true;
-                            break;
-                        }
-                    }
-                    if (!failed) {
-                        toTable("updated attribute", "attribute", "new value", attrList);
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(updateErrorMessage);
-                }
-                break;
-            case DELETE:
-                final String deleteErrorMessage = "configuration --delete {CONF-NAME} {CONF-NAME} [...]";
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            configurationService.delete(parameter);
-                            Messages.printDeletedMessage("Configuration", parameter);
-                        } catch (final SyncopeClientException | WebServiceException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Configuration", parameter);
-                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
-                                Messages.printMessage("You cannot delete configuration", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                            break;
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(deleteErrorMessage);
-                }
-                break;
-            case EXPORT:
-                final String exportErrorMessage = "configuration --export {WHERE-DIR}";
-                if (parameters.length == 1) {
-                    try {
-                        XMLUtils.createXMLFile((SequenceInputStream) configurationService.export().getEntity(),
-                                parameters[0] + EXPORT_FILE_NAME);
-                        System.out.println(" - " + parameters[0] + EXPORT_FILE_NAME + " successfully created");
-                    } catch (final IOException ex) {
-                        Messages.printMessage(ex.getMessage());
-                    } catch (ParserConfigurationException | SAXException | TransformerConfigurationException ex) {
-                        LOG.error("Error creating content.xml file in {} directory", parameters[0], ex);
-                        Messages.printMessage(
-                                "Error creating " + parameters[0] + EXPORT_FILE_NAME + " " + ex.getMessage());
-                        break;
-                    } catch (final TransformerException ex) {
-                        LOG.error("Error creating content.xml file in {} directory", parameters[0], ex);
-                        if (ex.getCause() instanceof FileNotFoundException) {
-                            Messages.printMessage("Permission denied on " + parameters[0]);
-                        } else {
-                            Messages.printMessage(
-                                    "Error creating " + parameters[0] + EXPORT_FILE_NAME + " " + ex.getMessage());
-                        }
-                        break;
-                    } catch (final SyncopeClientException ex) {
-                        LOG.error("Error calling configuration service", ex);
-                        Messages.printMessage("Error calling configuration service " + ex.getMessage());
-                        break;
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(exportErrorMessage);
-                }
-                break;
-            case HELP:
-                System.out.println(HELP_MESSAGE);
-                break;
-            default:
-                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
-                break;
-        }
-    }
-
-    private void toTable(final String tableTitle,
-            final String firstHeader,
-            final String seconHeader,
-            final Set<AttrTO> attrList) {
-        int maxFirstColumnLenght = 0;
-        int maxSecondColumnLenght = 0;
-        final Map<String, String> attributes = new HashMap<>();
-        for (final AttrTO attrTO : attrList) {
-            String value = attrTO.getValues().toString();
-            value = value.substring(0, value.length() - 1);
-            value = value.substring(1, value.length());
-            attributes.put(attrTO.getSchema(), value);
-            if (attrTO.getSchema().length() > maxFirstColumnLenght) {
-                maxFirstColumnLenght = attrTO.getSchema().length();
-            }
-
-            if (value.length() > maxSecondColumnLenght) {
-                maxSecondColumnLenght = attrTO.getSchema().length();
-            }
-        }
-        final TwoColumnTable loggerTableResult = new TwoColumnTable(
-                tableTitle,
-                firstHeader, maxFirstColumnLenght,
-                seconHeader, maxSecondColumnLenght);
-        loggerTableResult.printTable(attributes);
-    }
-
-    @Override
-    public String getHelpMessage() {
-        return HELP_MESSAGE;
-    }
-
-    private enum Options {
-
-        HELP("--help"),
-        GET("--get"),
-        READ("--read"),
-        UPDATE("--update"),
-        DELETE("--delete"),
-        EXPORT("--export");
-
-        private final String optionName;
-
-        Options(final String optionName) {
-            this.optionName = optionName;
-        }
-
-        public String getOptionName() {
-            return optionName;
-        }
-
-        public boolean equalsOptionName(final String otherName) {
-            return (otherName == null) ? false : optionName.equals(otherName);
-        }
-
-        public static Options fromName(final String name) {
-            Options optionToReturn = HELP;
-            for (final Options option : Options.values()) {
-                if (option.equalsOptionName(name)) {
-                    optionToReturn = option;
-                }
-            }
-            return optionToReturn;
-        }
-
-        public static List<String> toList() {
-            final List<String> options = new ArrayList<>();
-            for (final Options value : values()) {
-                options.add(value.getOptionName());
-            }
-            return options;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/AbstractConfigurationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/AbstractConfigurationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/AbstractConfigurationCommand.java
new file mode 100644
index 0000000..59fc423
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/AbstractConfigurationCommand.java
@@ -0,0 +1,30 @@
+/*
+ * 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.cli.commands.configuration;
+
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.common.rest.api.service.ConfigurationService;
+
+public class AbstractConfigurationCommand {
+
+    protected final ConfigurationService configurationService = SyncopeServices.get(ConfigurationService.class);
+
+    protected final ConfigurationResultManager configurationResultManager = new ConfigurationResultManager();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationCommand.java
new file mode 100644
index 0000000..d74ea78
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationCommand.java
@@ -0,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.cli.commands.configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.commands.AbstractCommand;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Command(name = "configuration")
+public class ConfigurationCommand extends AbstractCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ConfigurationCommand.class);
+
+    private static final String HELP_MESSAGE = "Usage: configuration [options]\n"
+            + "  Options:\n"
+            + "    --help \n"
+            + "    --get \n"
+            + "    --read \n"
+            + "       Syntax: --read {CONF-NAME} {CONF-NAME} [...] \n"
+            + "    --update \n"
+            + "       Syntax: --update {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]\n"
+            + "    --delete \n"
+            + "       Syntax: --delete {CONF-NAME} {CONF-NAME} [...]\n"
+            + "    --export \n"
+            + "       Syntax: --export {WHERE-DIR}";
+
+    @Override
+    public void execute(final Input input) {
+        if (StringUtils.isBlank(input.getOption())) {
+            input.setOption(Options.HELP.getOptionName());
+        }
+
+        switch (Options.fromName(input.getOption())) {
+            case GET:
+                new ConfigurationGet().get();
+                break;
+            case READ:
+                new ConfigurationRead(input).read();
+                break;
+            case UPDATE:
+                new ConfigurationUpdate(input).update();
+                break;
+            case DELETE:
+                new ConfigurationDelete(input).delete();
+                break;
+            case EXPORT:
+                break;
+            case HELP:
+                System.out.println(HELP_MESSAGE);
+                break;
+            default:
+                new ConfigurationResultManager().defaultError(input.getOption(), HELP_MESSAGE);
+                break;
+        }
+    }
+
+    @Override
+    public String getHelpMessage() {
+        return HELP_MESSAGE;
+    }
+
+    private enum Options {
+
+        HELP("--help"),
+        GET("--get"),
+        READ("--read"),
+        UPDATE("--update"),
+        DELETE("--delete"),
+        EXPORT("--export");
+
+        private final String optionName;
+
+        Options(final String optionName) {
+            this.optionName = optionName;
+        }
+
+        public String getOptionName() {
+            return optionName;
+        }
+
+        public boolean equalsOptionName(final String otherName) {
+            return (otherName == null) ? false : optionName.equals(otherName);
+        }
+
+        public static Options fromName(final String name) {
+            Options optionToReturn = HELP;
+            for (final Options option : Options.values()) {
+                if (option.equalsOptionName(name)) {
+                    optionToReturn = option;
+                }
+            }
+            return optionToReturn;
+        }
+
+        public static List<String> toList() {
+            final List<String> options = new ArrayList<>();
+            for (final Options value : values()) {
+                options.add(value.getOptionName());
+            }
+            return options;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationDelete.java
new file mode 100644
index 0000000..4f8c227
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationDelete.java
@@ -0,0 +1,57 @@
+/*
+ * 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.cli.commands.configuration;
+
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+
+public class ConfigurationDelete extends AbstractConfigurationCommand {
+
+    private static final String DELETE_HELP_MESSAGE = "configuration --delete {CONF-NAME} {CONF-NAME} [...]";
+
+    private final Input input;
+
+    public ConfigurationDelete(final Input input) {
+        this.input = input;
+    }
+
+    public void delete() {
+        if (input.parameterNumber() >= 1) {
+            for (final String parameter : input.getParameters()) {
+                try {
+                    configurationService.delete(parameter);
+                    configurationResultManager.deletedMessage("Configuration", parameter);
+                } catch (final SyncopeClientException | WebServiceException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        configurationResultManager.notFoundError("Configuration", parameter);
+                    } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
+                        configurationResultManager.genericError("You cannot delete configuration", parameter);
+                    } else {
+                        configurationResultManager.genericError(ex.getMessage());
+                    }
+                    break;
+                }
+            }
+        } else {
+            configurationResultManager.commandOptionError(DELETE_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationExport.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationExport.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationExport.java
new file mode 100644
index 0000000..0bc274f
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationExport.java
@@ -0,0 +1,71 @@
+/*
+ * 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.cli.commands.configuration;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.SequenceInputStream;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.util.XMLUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.xml.sax.SAXException;
+
+public class ConfigurationExport extends AbstractConfigurationCommand {
+
+    private static final String EXPORT_HELP_MESSAGE = "configuration --export {WHERE-DIR}";
+
+    private static final String EXPORT_FILE_NAME = "/content.xml";
+
+    private final Input input;
+
+    public ConfigurationExport(final Input input) {
+        this.input = input;
+    }
+
+    public void export() {
+        if (input.parameterNumber() == 1) {
+            try {
+                XMLUtils.createXMLFile(
+                        (SequenceInputStream) configurationService.export().getEntity(),
+                        input.firstParameter() + EXPORT_FILE_NAME);
+                configurationResultManager.genericError(
+                        input.firstParameter() + EXPORT_FILE_NAME + " successfully created");
+            } catch (final IOException ex) {
+                configurationResultManager.genericError(ex.getMessage());
+            } catch (ParserConfigurationException | SAXException | TransformerConfigurationException ex) {
+                configurationResultManager.genericError(
+                        "Error creating " + input.firstParameter() + EXPORT_FILE_NAME + " " + ex.getMessage());
+            } catch (final TransformerException ex) {
+                if (ex.getCause() instanceof FileNotFoundException) {
+                    configurationResultManager.genericError("Permission denied on " + input.firstParameter());
+                } else {
+                    configurationResultManager.genericError(
+                            "Error creating " + input.firstParameter() + EXPORT_FILE_NAME + " " + ex.getMessage());
+                }
+            } catch (final SyncopeClientException ex) {
+                configurationResultManager.genericError("Error calling configuration service " + ex.getMessage());
+            }
+        } else {
+            configurationResultManager.commandOptionError(EXPORT_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
new file mode 100644
index 0000000..91f3dce
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
@@ -0,0 +1,36 @@
+/*
+ * 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.cli.commands.configuration;
+
+import java.util.LinkedList;
+
+public class ConfigurationGet extends AbstractConfigurationCommand {
+
+    public ConfigurationGet() {
+    }
+
+    public void get() {
+        try {
+            configurationResultManager.fromGet(new LinkedList<>(configurationService.list().getPlainAttrs()));
+        } catch (final Exception ex) {
+            configurationResultManager.genericError(ex.getMessage());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationRead.java
new file mode 100644
index 0000000..801f01d
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationRead.java
@@ -0,0 +1,62 @@
+/*
+ * 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.cli.commands.configuration;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AttrTO;
+
+public class ConfigurationRead extends AbstractConfigurationCommand {
+
+    private static final String READ_HELP_MESSAGE = "configuration --read {CONF-NAME} {CONF-NAME} [...]";
+
+    private final Input input;
+
+    public ConfigurationRead(final Input input) {
+        this.input = input;
+    }
+
+    public void read() {
+        if (input.parameterNumber() >= 1) {
+            final LinkedList<AttrTO> attrList = new LinkedList<>();
+            boolean failed = false;
+            for (final String parameter : input.getParameters()) {
+                try {
+                    attrList.add(configurationService.get(parameter));
+                } catch (final SyncopeClientException | WebServiceException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        configurationResultManager.notFoundError("Configuration", parameter);
+                    } else {
+                        configurationResultManager.genericError(ex.getMessage());
+                    }
+                    failed = true;
+                    break;
+                }
+            }
+            if (!failed) {
+                configurationResultManager.fromGet(attrList);
+            }
+        } else {
+            configurationResultManager.commandOptionError(READ_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationResultManager.java
new file mode 100644
index 0000000..446d08a
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationResultManager.java
@@ -0,0 +1,53 @@
+/*
+ * 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.cli.commands.configuration;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+import org.apache.syncope.client.cli.messages.Table;
+import org.apache.syncope.common.lib.to.AttrTO;
+
+public class ConfigurationResultManager extends CommonsResultManager {
+
+    public void fromGet(final LinkedList<AttrTO> attrTOs) {
+        fromCommandToView("syncope configuration", attrTOs);
+    }
+
+    public void fromRead(final LinkedList<AttrTO> attrTOs) {
+        fromCommandToView("selected configuration attributes", attrTOs);
+    }
+    
+    public void fromUpdate(final LinkedList<AttrTO> attrTOs) {
+        fromCommandToView("updated configuration attributes", attrTOs);
+    }
+
+    private void fromCommandToView(final String title, final LinkedList<AttrTO> attrTOs) {
+        final Table.TableBuilder tableBuilder
+                = new Table.TableBuilder(title).header("attribute").header("value");
+        for (final AttrTO attrTO : attrTOs) {
+            String attrValue = attrTO.getValues().toString();
+            attrValue = attrValue.substring(0, attrValue.length() - 1);
+            attrValue = attrValue.substring(1, attrValue.length());
+            tableBuilder.rowValues(
+                    new LinkedList(Arrays.asList(attrTO.getSchema(), attrValue)));
+        }
+        tableBuilder.build().print();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationUpdate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationUpdate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationUpdate.java
new file mode 100644
index 0000000..9be74e2
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationUpdate.java
@@ -0,0 +1,76 @@
+/*
+ * 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.cli.commands.configuration;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AttrTO;
+
+public class ConfigurationUpdate extends AbstractConfigurationCommand {
+
+    private static final String UPDATE_HELP_MESSAGE
+            = "configuration --update {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]";
+
+    private final Input input;
+
+    public ConfigurationUpdate(final Input input) {
+        this.input = input;
+    }
+
+    public void update() {
+        if (input.parameterNumber() >= 1) {
+            Input.PairParameter pairParameter = null;
+            AttrTO attrTO;
+            final LinkedList<AttrTO> attrList = new LinkedList<>();
+            boolean failed = false;
+            for (final String parameter : input.getParameters()) {
+                try {
+                    pairParameter = input.toPairParameter(parameter);
+                    attrTO = configurationService.get(pairParameter.getKey());
+                    attrTO.getValues().clear();
+                    attrTO.getValues().add(pairParameter.getValue());
+                    configurationService.set(attrTO);
+                    attrList.add(attrTO);
+                } catch (final IllegalArgumentException ex) {
+                    configurationResultManager.genericError(ex.getMessage(), UPDATE_HELP_MESSAGE);
+                    failed = true;
+                    break;
+                } catch (final SyncopeClientException | WebServiceException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        configurationResultManager.notFoundError("Configuration", pairParameter.getKey());
+                    } else if (ex.getMessage().startsWith("InvalidValues")) {
+                        configurationResultManager.genericError(
+                                pairParameter.getValue() + " is not a valid value for " + pairParameter.getKey());
+                    } else {
+                        configurationResultManager.genericError(ex.getMessage());
+                    }
+                    failed = true;
+                    break;
+                }
+            }
+            if (!failed) {
+                configurationResultManager.fromUpdate(attrList);
+            }
+        } else {
+            configurationResultManager.commandOptionError(UPDATE_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
index 4654cb6..3782eac 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
@@ -25,6 +25,6 @@ public class AbstractLoggerCommand {
 
     protected final LoggerService loggerService = SyncopeServices.get(LoggerService.class);
     
-    protected final ResultManager resultManager = new ResultManager();
+    protected final LoggerResultManager loggerResultManager = new LoggerResultManager();
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
index 34acc25..134c294 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
@@ -24,7 +24,6 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.client.cli.commands.AbstractCommand;
-import org.apache.syncope.client.cli.messages.Messages;
 
 @Command(name = "logger")
 public class LoggerCommand extends AbstractCommand {
@@ -73,7 +72,7 @@ public class LoggerCommand extends AbstractCommand {
                 System.out.println(HELP_MESSAGE);
                 break;
             default:
-                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
+                new LoggerResultManager().defaultError(input.getOption(), HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
index d70aad1..29d60ad 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
@@ -52,16 +52,16 @@ public class LoggerCreate extends AbstractLoggerCommand {
                     loggerService.update(LoggerType.LOG, loggerTO);
                     loggerTOs.add(loggerTO);
                 } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
-                    resultManager.typeNotValidError(input.firstParameter());
+                    loggerResultManager.typeNotValidError(input.firstParameter());
                     failed = true;
                     break;
                 }
             }
             if (!failed) {
-                resultManager.fromUpdate(loggerTOs);
+                loggerResultManager.fromUpdate(loggerTOs);
             }
         } else {
-            resultManager.commandOptionError(CREATE_HELP_MESSAGE);
+            loggerResultManager.commandOptionError(CREATE_HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
index 44f39ee..6614f07 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
@@ -18,11 +18,9 @@
  */
 package org.apache.syncope.client.cli.commands.logger;
 
-import java.util.LinkedList;
 import javax.xml.ws.WebServiceException;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.LoggerTO;
 import org.apache.syncope.common.lib.types.LoggerType;
 
 public class LoggerDelete extends AbstractLoggerCommand {
@@ -37,25 +35,20 @@ public class LoggerDelete extends AbstractLoggerCommand {
 
     public void delete() {
         if (input.parameterNumber() >= 1) {
-            final LinkedList<LoggerTO> loggerTOs = new LinkedList<>();
-            boolean failed = false;
             for (final String parameter : input.getParameters()) {
                 try {
                     loggerService.delete(LoggerType.LOG, parameter);
+                    loggerResultManager.deletedMessage("Logger", parameter);
                 } catch (final WebServiceException | SyncopeClientException ex) {
                     if (ex.getMessage().startsWith("NotFound")) {
-                        resultManager.notFoundError(parameter);
+                        loggerResultManager.notFoundError("Logger", parameter);
                     } else {
-                        resultManager.genericError(ex.getMessage());
+                        loggerResultManager.genericError(ex.getMessage());
                     }
-                    failed = true;
                 }
             }
-            if (!failed) {
-                resultManager.fromDelete(loggerTOs);
-            }
         } else {
-            resultManager.commandOptionError(DELETE_HELP_MESSAGE);
+            loggerResultManager.commandOptionError(DELETE_HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
index bee7e7c..f65da34 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
@@ -29,9 +29,9 @@ public class LoggerList extends AbstractLoggerCommand {
 
     public void list() {
         try {
-            resultManager.fromList(new LinkedList<>(loggerService.list(LoggerType.LOG)));
+            loggerResultManager.fromList(new LinkedList<>(loggerService.list(LoggerType.LOG)));
         } catch (final SyncopeClientException ex) {
-            resultManager.genericError("Error: " + ex.getMessage());
+            loggerResultManager.genericError("Error: " + ex.getMessage());
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
index 3cbca46..c796c47 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
@@ -44,19 +44,19 @@ public class LoggerRead extends AbstractLoggerCommand {
                     loggerTOs.add(loggerService.read(LoggerType.LOG, parameter));
                 } catch (final SyncopeClientException | WebServiceException ex) {
                     if (ex.getMessage().startsWith("NotFound")) {
-                        resultManager.notFoundError(parameter);
+                        loggerResultManager.notFoundError("Logger", parameter);
                     } else {
-                        resultManager.genericError("Error: " + ex.getMessage());
+                        loggerResultManager.genericError("Error: " + ex.getMessage());
                     }
                     failed = true;
                     break;
                 }
             }
             if (!failed) {
-                resultManager.fromRead(loggerTOs);
+                loggerResultManager.fromRead(loggerTOs);
             }
         } else {
-            resultManager.commandOptionError(READ_HELP_MESSAGE);
+            loggerResultManager.commandOptionError(READ_HELP_MESSAGE);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerResultManager.java
new file mode 100644
index 0000000..1a686cd
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerResultManager.java
@@ -0,0 +1,61 @@
+/*
+ * 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.cli.commands.logger;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+import org.apache.syncope.client.cli.messages.Table;
+import org.apache.syncope.common.lib.to.LoggerTO;
+
+public class LoggerResultManager extends CommonsResultManager {
+
+    public void fromList(final LinkedList<LoggerTO> loggerTOs) {
+        fromCommandToView("list loggers", "level", loggerTOs);
+    }
+
+    public void fromRead(final LinkedList<LoggerTO> loggerTOs) {
+        fromCommandToView("read loggers", "level", loggerTOs);
+    }
+
+    public void fromCreate(final LinkedList<LoggerTO> loggerTOs) {
+        fromCommandToView("created loggers", "level", loggerTOs);
+    }
+
+    public void fromUpdate(final LinkedList<LoggerTO> loggerTOs) {
+        fromCommandToView("updated loggers", "new level", loggerTOs);
+    }
+
+    public void fromDelete(final LinkedList<LoggerTO> loggerTOs) {
+        fromCommandToView("deleted loggers", "new level", loggerTOs);
+    }
+
+    private void fromCommandToView(final String title,
+            final String secondHeader,
+            final LinkedList<LoggerTO> loggerTOs) {
+        final Table.TableBuilder tableBuilder
+                = new Table.TableBuilder(title).header("logger").header(secondHeader);
+        for (final LoggerTO loggerTO : loggerTOs) {
+            tableBuilder.rowValues(
+                    new LinkedList(Arrays.asList(loggerTO.getKey(), loggerTO.getLevel().getLevel().name())));
+        }
+        tableBuilder.build().print();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
index d309c4c..cbfc196 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
@@ -52,23 +52,23 @@ public class LoggerUpdate extends AbstractLoggerCommand {
                     loggerTOs.add(loggerTO);
                 } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
                     if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                        resultManager.typeNotValidError(input.firstParameter());
+                        loggerResultManager.typeNotValidError(input.firstParameter());
                     } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
-                        resultManager.genericError(ex.getMessage(), UPDATE_HELP_MESSAGE);
+                        loggerResultManager.genericError(ex.getMessage(), UPDATE_HELP_MESSAGE);
                     } else if (ex.getMessage().startsWith("NotFound")) {
-                        resultManager.notFoundError(parameter);
+                        loggerResultManager.notFoundError("Logger", parameter);
                     } else {
-                        resultManager.genericError(ex.getMessage(), UPDATE_HELP_MESSAGE);
+                        loggerResultManager.genericError(ex.getMessage(), UPDATE_HELP_MESSAGE);
                     }
                     failed = true;
                     break;
                 }
             }
             if (!failed) {
-                resultManager.fromUpdate(loggerTOs);
+                loggerResultManager.fromUpdate(loggerTOs);
             }
         } else {
-            resultManager.commandOptionError(UPDATE_HELP_MESSAGE);
+            loggerResultManager.commandOptionError(UPDATE_HELP_MESSAGE);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
index 3393ae4..305fa30 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
@@ -47,19 +47,19 @@ public class LoggerUpdateAll extends AbstractLoggerCommand {
                     loggerTOs.add(loggerTO);
                 } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
                     if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                        resultManager.typeNotValidError(input.firstParameter());
+                        loggerResultManager.typeNotValidError(input.firstParameter());
                     } else {
-                        resultManager.genericError(ex.getMessage(), UPDATE_ALL_HELP_MESSAGE);
+                        loggerResultManager.genericError(ex.getMessage(), UPDATE_ALL_HELP_MESSAGE);
                     }
                     failed = true;
                     break;
                 }
             }
             if (!failed) {
-                resultManager.fromUpdate(loggerTOs);
+                loggerResultManager.fromUpdate(loggerTOs);
             }
         } else {
-            resultManager.commandOptionError(UPDATE_ALL_HELP_MESSAGE);
+            loggerResultManager.commandOptionError(UPDATE_ALL_HELP_MESSAGE);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b9cd592/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java
deleted file mode 100644
index e993eb7..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.cli.commands.logger;
-
-import java.util.Arrays;
-import java.util.LinkedList;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.messages.Table;
-import org.apache.syncope.client.cli.util.CommandUtils;
-import org.apache.syncope.common.lib.to.LoggerTO;
-import org.apache.syncope.common.lib.types.LoggerLevel;
-
-public class ResultManager {
-
-    public void notFoundError(final String parameter) {
-        Messages.printNofFoundMessage("Logger", parameter);
-    }
-
-    public void typeNotValidError(final String parameter) {
-        Messages.printTypeNotValidMessage("logger level", parameter, CommandUtils.fromEnumToArray(LoggerLevel.class));
-    }
-
-    public void commandOptionError(final String message) {
-        Messages.printCommandOptionMessage(message);
-    }
-
-    public void genericError(final String... messages) {
-        Messages.printMessage(messages);
-    }
-
-    public void fromList(final LinkedList<LoggerTO> loggerTOs) {
-        fromCommandToView("list loggers", "level", loggerTOs);
-    }
-
-    public void fromRead(final LinkedList<LoggerTO> loggerTOs) {
-        fromCommandToView("read loggers", "level", loggerTOs);
-    }
-
-    public void fromCreate(final LinkedList<LoggerTO> loggerTOs) {
-        fromCommandToView("created loggers", "level", loggerTOs);
-    }
-
-    public void fromUpdate(final LinkedList<LoggerTO> loggerTOs) {
-        fromCommandToView("updated loggers", "new level", loggerTOs);
-    }
-
-    public void fromDelete(final LinkedList<LoggerTO> loggerTOs) {
-        fromCommandToView("deleted loggers", "new level", loggerTOs);
-    }
-
-    private void fromCommandToView(final String title,
-            final String secondHeader,
-            final LinkedList<LoggerTO> loggerTOs) {
-        final Table.TableBuilder tableBuilder
-                = new Table.TableBuilder(title).header("logger").header(secondHeader);
-        for (final LoggerTO loggerTO : loggerTOs) {
-            tableBuilder.rowValues(
-                    new LinkedList(Arrays.asList(loggerTO.getKey(), loggerTO.getLevel().getLevel().name())));
-        }
-        tableBuilder.build().print();
-    }
-
-}


[21/54] [abbrv] syncope git commit: ConnId AD 1.3.0-SNAPSHOT

Posted by fm...@apache.org.
ConnId AD 1.3.0-SNAPSHOT


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

Branch: refs/heads/SYNCOPE-156
Commit: fc208d2d00a6821a3c0a369f3010e0cc3a2b343a
Parents: 4e0783e
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Mon Oct 19 18:09:11 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Mon Oct 19 18:09:11 2015 +0200

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/fc208d2d/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 78179bf..b7ee843 100644
--- a/pom.xml
+++ b/pom.xml
@@ -324,7 +324,7 @@ under the License.
     <connid.database.version>2.2.3-SNAPSHOT</connid.database.version>
     <connid.csvdir.version>0.8.2</connid.csvdir.version>
     <connid.ldap.version>1.5.0-SNAPSHOT</connid.ldap.version>
-    <connid.ad.version>1.2.3</connid.ad.version>
+    <connid.ad.version>1.3.0-SNAPSHOT</connid.ad.version>
 
     <cxf.version>3.1.4-SNAPSHOT</cxf.version>
 


[40/54] [abbrv] syncope git commit: [SYNCOPE-709] Refactoring completed

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
index 7de863e..91da759 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
@@ -45,7 +45,6 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.cxf.common.util.Base64Utility;
 import org.apache.cxf.helpers.IOUtils;
 import org.apache.syncope.client.lib.SyncopeClient;
-import org.apache.syncope.common.lib.AnyOperations;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.patch.AssociationPatch;
@@ -137,7 +136,6 @@ public class UserITCase extends AbstractITCase {
         userTO.getPlainAttrs().add(attrTO("email", email));
         userTO.getPlainAttrs().add(attrTO("loginDate", DATE_FORMAT.get().format(new Date())));
         userTO.getDerAttrs().add(attrTO("cn", null));
-        userTO.getVirAttrs().add(attrTO("virtualdata", "virtualvalue"));
         return userTO;
     }
 
@@ -154,7 +152,6 @@ public class UserITCase extends AbstractITCase {
 
         // create a new user
         UserTO userTO = getUniqueSampleTO("xxx@xxx.xxx");
-
         userTO.setPassword("password123");
         userTO.getResources().add(RESOURCE_NAME_NOPROPAGATION);
 
@@ -173,7 +170,6 @@ public class UserITCase extends AbstractITCase {
 
         // get last task
         PropagationTaskTO taskTO = taskService.read(newMaxId);
-
         assertNotNull(taskTO);
         assertTrue(taskTO.getExecutions().isEmpty());
     }
@@ -387,15 +383,6 @@ public class UserITCase extends AbstractITCase {
         // check for changePwdDate
         assertNotNull(newUserTO.getCreationDate());
 
-        // 2. check for virtual attribute value
-        newUserTO = userService.read(newUserTO.getKey());
-        assertNotNull(newUserTO);
-
-        assertNotNull(newUserTO.getVirAttrMap());
-        assertNotNull(newUserTO.getVirAttrMap().get("virtualdata").getValues());
-        assertFalse(newUserTO.getVirAttrMap().get("virtualdata").getValues().isEmpty());
-        assertEquals("virtualvalue", newUserTO.getVirAttrMap().get("virtualdata").getValues().get(0));
-
         // get the new task list
         tasks = taskService.list(
                 TaskType.PROPAGATION,
@@ -751,7 +738,7 @@ public class UserITCase extends AbstractITCase {
 
         long newMaxKey = tasks.getResult().iterator().next().getKey();
 
-        // default configuration for ws-target-resource2:
+        // default configuration for ws-target-resource2 during create:
         // only failed executions have to be registered
         // --> no more tasks/executions should be added
         assertEquals(newMaxKey, maxKey);
@@ -762,7 +749,7 @@ public class UserITCase extends AbstractITCase {
         UserPatch userPatch = new UserPatch();
         userPatch.setKey(userTO.getKey());
 
-        userPatch.getPlainAttrs().add(attrAddReplacePatch("surname", "surname"));
+        userPatch.getPlainAttrs().add(attrAddReplacePatch("surname", "surname2"));
 
         userTO = updateUser(userPatch);
 
@@ -776,11 +763,11 @@ public class UserITCase extends AbstractITCase {
         maxKey = newMaxKey;
         newMaxKey = tasks.getResult().iterator().next().getKey();
 
-        // default configuration for ws-target-resource2:
+        // default configuration for ws-target-resource2 during update:
         // all update executions have to be registered
         assertTrue(newMaxKey > maxKey);
 
-        final PropagationTaskTO taskTO = taskService.read(newMaxKey);
+        PropagationTaskTO taskTO = taskService.read(newMaxKey);
 
         assertNotNull(taskTO);
         assertEquals(1, taskTO.getExecutions().size());
@@ -1004,37 +991,6 @@ public class UserITCase extends AbstractITCase {
     }
 
     @Test
-    public void issue270() {
-        // 1. create a new user without virtual attributes
-        UserTO original = getUniqueSampleTO("issue270@syncope.apache.org");
-        // be sure to remove all virtual attributes
-        original.getVirAttrs().clear();
-
-        original = createUser(original);
-
-        assertNotNull(original);
-
-        assertTrue(original.getVirAttrs().isEmpty());
-
-        UserTO toBeUpdated = userService.read(original.getKey());
-
-        AttrTO virtual = attrTO("virtualdata", "virtualvalue");
-        toBeUpdated.getVirAttrs().add(virtual);
-
-        // 2. try to update by adding a resource, but no password: must fail
-        UserPatch userPatch = AnyOperations.diff(toBeUpdated, original, false);
-        assertNotNull(userPatch);
-
-        toBeUpdated = updateUser(userPatch);
-        assertNotNull(toBeUpdated);
-
-        assertFalse(toBeUpdated.getVirAttrs().isEmpty());
-        assertNotNull(toBeUpdated.getVirAttrs().iterator().next());
-
-        assertEquals(virtual.getSchema(), toBeUpdated.getVirAttrs().iterator().next().getSchema());
-    }
-
-    @Test
     public final void issue280() {
         UserTO userTO = getUniqueSampleTO("issue280@syncope.apache.org");
         userTO.getResources().clear();
@@ -1353,6 +1309,7 @@ public class UserITCase extends AbstractITCase {
         // create user and check virtual attribute value propagation
         // ----------------------------------
         UserTO userTO = getUniqueSampleTO("syncope267@apache.org");
+        userTO.getVirAttrs().add(attrTO("virtualdata", "virtualvalue"));
         userTO.getResources().clear();
         userTO.getResources().add(RESOURCE_NAME_DBVIRATTR);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirAttrITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirAttrITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirAttrITCase.java
index 1856eee..e96026f 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirAttrITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirAttrITCase.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.fit.core.reference;
 
+import static org.apache.syncope.fit.core.reference.AbstractITCase.getUUIDString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -25,14 +26,15 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.Locale;
 import java.util.Map;
+import javax.ws.rs.core.Response;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.SerializationUtils;
-import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.PasswordPatch;
 import org.apache.syncope.common.lib.patch.StatusPatch;
 import org.apache.syncope.common.lib.patch.StringPatchItem;
 import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.ConnInstanceTO;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
@@ -43,13 +45,16 @@ import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.ProvisionTO;
 import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.to.VirSchemaTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
 import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
+import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.syncope.common.lib.types.StatusPatchType;
+import org.apache.syncope.common.rest.api.service.AnyTypeClassService;
 import org.apache.syncope.common.rest.api.service.ResourceService;
 import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.junit.FixMethodOrder;
@@ -63,38 +68,60 @@ public class VirAttrITCase extends AbstractITCase {
     @Test
     public void issueSYNCOPE16() {
         UserTO userTO = UserITCase.getUniqueSampleTO("issue16@apache.org");
-
+        userTO.getVirAttrs().add(attrTO("virtualdata", "virtualvalue"));
+        userTO.getResources().add(RESOURCE_NAME_DBVIRATTR);
         userTO.getMemberships().add(new MembershipTO.Builder().group(8L).build());
 
         // 1. create user
-        UserTO actual = createUser(userTO);
-        assertNotNull(actual);
+        userTO = createUser(userTO);
+        assertNotNull(userTO);
 
         // 2. check for virtual attribute value
-        actual = userService.read(actual.getKey());
-        assertNotNull(actual);
-        assertEquals("virtualvalue", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
+        userTO = userService.read(userTO.getKey());
+        assertNotNull(userTO);
+        assertEquals("virtualvalue", userTO.getVirAttrMap().get("virtualdata").getValues().get(0));
 
         UserPatch userPatch = new UserPatch();
-        userPatch.setKey(actual.getKey());
-        userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "virtualupdated"));
+        userPatch.setKey(userTO.getKey());
+        userPatch.getVirAttrs().add(attrTO("virtualdata", "virtualupdated"));
 
         // 3. update virtual attribute
-        actual = updateUser(userPatch);
-        assertNotNull(actual);
+        userTO = updateUser(userPatch);
+        assertNotNull(userTO);
 
         // 4. check for virtual attribute value
-        actual = userService.read(actual.getKey());
-        assertNotNull(actual);
-        assertEquals("virtualupdated", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
+        userTO = userService.read(userTO.getKey());
+        assertNotNull(userTO);
+        assertEquals("virtualupdated", userTO.getVirAttrMap().get("virtualdata").getValues().get(0));
     }
 
     @Test
     public void issueSYNCOPE260() {
+        // create new virtual schema for the resource below
+        ResourceTO ws2 = resourceService.read(RESOURCE_NAME_WS2);
+        ProvisionTO provision = ws2.getProvision(AnyTypeKind.USER.name());
+        assertNotNull(provision);
+
+        VirSchemaTO virSchema = new VirSchemaTO();
+        virSchema.setKey("syncope260" + getUUIDString());
+        virSchema.setExtAttrName("companyName");
+        virSchema.setProvision(provision.getKey());
+        virSchema = createSchema(SchemaType.VIRTUAL, virSchema);
+        assertNotNull(virSchema);
+
+        AnyTypeClassTO newClass = new AnyTypeClassTO();
+        newClass.setKey("syncope260" + getUUIDString());
+        newClass.getVirSchemas().add(virSchema.getKey());
+        Response response = anyTypeClassService.create(newClass);
+        assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatusInfo().getStatusCode());
+        newClass = getObject(response.getLocation(), AnyTypeClassService.class, AnyTypeClassTO.class);
+
         // ----------------------------------
         // create user and check virtual attribute value propagation
         // ----------------------------------
         UserTO userTO = UserITCase.getUniqueSampleTO("260@a.com");
+        userTO.getAuxClasses().add(newClass.getKey());
+        userTO.getVirAttrs().add(attrTO(virSchema.getKey(), "virtualvalue"));
         userTO.getResources().add(RESOURCE_NAME_WS2);
 
         userTO = createUser(userTO);
@@ -105,8 +132,7 @@ public class VirAttrITCase extends AbstractITCase {
 
         ConnObjectTO connObjectTO =
                 resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
-        assertNotNull(connObjectTO);
-        assertEquals("virtualvalue", connObjectTO.getPlainAttrMap().get("NAME").getValues().get(0));
+        assertEquals("virtualvalue", connObjectTO.getPlainAttrMap().get("COMPANYNAME").getValues().get(0));
         // ----------------------------------
 
         // ----------------------------------
@@ -114,17 +140,16 @@ public class VirAttrITCase extends AbstractITCase {
         // ----------------------------------
         UserPatch userPatch = new UserPatch();
         userPatch.setKey(userTO.getKey());
-        userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "virtualvalue2"));
+        userPatch.getVirAttrs().add(attrTO(virSchema.getKey(), "virtualvalue2"));
 
         userTO = updateUser(userPatch);
         assertNotNull(userTO);
         assertFalse(userTO.getPropagationStatusTOs().isEmpty());
-        assertEquals("ws-target-resource-2", userTO.getPropagationStatusTOs().get(0).getResource());
+        assertEquals(RESOURCE_NAME_WS2, userTO.getPropagationStatusTOs().get(0).getResource());
         assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 
         connObjectTO = resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
-        assertNotNull(connObjectTO);
-        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("NAME").getValues().get(0));
+        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("COMPANYNAME").getValues().get(0));
         // ----------------------------------
 
         // ----------------------------------
@@ -137,9 +162,7 @@ public class VirAttrITCase extends AbstractITCase {
         assertEquals("suspended", userTO.getStatus());
 
         connObjectTO = resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
-        assertNotNull(connObjectTO);
-        assertFalse(connObjectTO.getPlainAttrMap().get("NAME").getValues().isEmpty());
-        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("NAME").getValues().get(0));
+        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("COMPANYNAME").getValues().get(0));
 
         statusPatch = new StatusPatch();
         statusPatch.setKey(userTO.getKey());
@@ -148,9 +171,7 @@ public class VirAttrITCase extends AbstractITCase {
         assertEquals("active", userTO.getStatus());
 
         connObjectTO = resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
-        assertNotNull(connObjectTO);
-        assertFalse(connObjectTO.getPlainAttrMap().get("NAME").getValues().isEmpty());
-        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("NAME").getValues().get(0));
+        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("COMPANYNAME").getValues().get(0));
         // ----------------------------------
 
         // ----------------------------------
@@ -167,36 +188,11 @@ public class VirAttrITCase extends AbstractITCase {
         assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 
         connObjectTO = resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
-        assertNotNull(connObjectTO);
         assertEquals("Surname2", connObjectTO.getPlainAttrMap().get("SURNAME").getValues().get(0));
 
-        // attribute "name" mapped on virtual attribute "virtualdata" shouldn't be changed
-        assertFalse(connObjectTO.getPlainAttrMap().get("NAME").getValues().isEmpty());
-        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("NAME").getValues().get(0));
-        // ----------------------------------
-
-        // ----------------------------------
-        // remove user virtual attribute and check virtual attribute value (reset)
-        // ----------------------------------
-        userPatch = new UserPatch();
-        userPatch.setKey(userTO.getKey());
-        userPatch.getVirAttrs().add(new AttrPatch.Builder().
-                operation(PatchOperation.DELETE).
-                attrTO(new AttrTO.Builder().schema("virtualdata").build()).build());
-
-        userTO = updateUser(userPatch);
-        assertNotNull(userTO);
-        assertTrue(userTO.getVirAttrs().isEmpty());
-        assertFalse(userTO.getPropagationStatusTOs().isEmpty());
-        assertEquals(RESOURCE_NAME_WS2, userTO.getPropagationStatusTOs().get(0).getResource());
-        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
-
-        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_WS2, AnyTypeKind.USER.name(), userTO.getKey());
-        assertNotNull(connObjectTO);
-
-        // attribute "name" mapped on virtual attribute "virtualdata" should be reset
-        assertTrue(connObjectTO.getPlainAttrMap().get("NAME").getValues() == null
-                || connObjectTO.getPlainAttrMap().get("NAME").getValues().isEmpty());
+        // virtual attribute value did not change
+        assertFalse(connObjectTO.getPlainAttrMap().get("COMPANYNAME").getValues().isEmpty());
+        assertEquals("virtualvalue2", connObjectTO.getPlainAttrMap().get("COMPANYNAME").getValues().get(0));
         // ----------------------------------
     }
 
@@ -241,7 +237,7 @@ public class VirAttrITCase extends AbstractITCase {
 
         UserPatch userPatch = new UserPatch();
         userPatch.setKey(actual.getKey());
-        userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "virtualupdated"));
+        userPatch.getVirAttrs().add(attrTO("virtualdata", "virtualupdated"));
 
         // 5. update virtual attribute
         actual = updateUser(userPatch);
@@ -256,36 +252,46 @@ public class VirAttrITCase extends AbstractITCase {
     @Test
     public void issueSYNCOPE397() {
         ResourceTO csv = resourceService.read(RESOURCE_NAME_CSV);
+
+        // change mapping of resource-csv
         MappingTO origMapping = SerializationUtils.clone(csv.getProvisions().get(0).getMapping());
         try {
-            // change mapping of resource-csv
-            assertNotNull(origMapping);
-            for (MappingItemTO item : csv.getProvisions().get(0).getMapping().getItems()) {
-                if ("email".equals(item.getIntAttrName())) {
-                    // unset internal attribute mail and set virtual attribute virtualdata as mapped to external email
-                    item.setIntMappingType(IntMappingType.UserVirtualSchema);
-                    item.setIntAttrName("virtualdata");
-                    item.setPurpose(MappingPurpose.BOTH);
-                    item.setExtAttrName("email");
-                }
-            }
+            // remove this mapping
+            CollectionUtils.filterInverse(csv.getProvisions().get(0).getMapping().getItems(),
+                    new Predicate<MappingItemTO>() {
+
+                        @Override
+                        public boolean evaluate(final MappingItemTO item) {
+                            return "email".equals(item.getIntAttrName());
+                        }
+                    });
 
             resourceService.update(csv);
             csv = resourceService.read(RESOURCE_NAME_CSV);
             assertNotNull(csv.getProvisions().get(0).getMapping());
 
-            boolean found = false;
-            for (MappingItemTO item : csv.getProvisions().get(0).getMapping().getItems()) {
-                if ("email".equals(item.getExtAttrName()) && "virtualdata".equals(item.getIntAttrName())) {
-                    found = true;
-                }
-            }
+            // create new virtual schema for the resource below
+            ProvisionTO provision = csv.getProvision(AnyTypeKind.USER.name());
+            assertNotNull(provision);
 
-            assertTrue(found);
+            VirSchemaTO virSchema = new VirSchemaTO();
+            virSchema.setKey("syncope397" + getUUIDString());
+            virSchema.setExtAttrName("email");
+            virSchema.setProvision(provision.getKey());
+            virSchema = createSchema(SchemaType.VIRTUAL, virSchema);
+            assertNotNull(virSchema);
+
+            AnyTypeClassTO newClass = new AnyTypeClassTO();
+            newClass.setKey("syncope397" + getUUIDString());
+            newClass.getVirSchemas().add(virSchema.getKey());
+            Response response = anyTypeClassService.create(newClass);
+            assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatusInfo().getStatusCode());
+            newClass = getObject(response.getLocation(), AnyTypeClassService.class, AnyTypeClassTO.class);
 
             // create a new user
             UserTO userTO = UserITCase.getUniqueSampleTO("397@syncope.apache.org");
             userTO.getAuxClasses().add("csv");
+            userTO.getAuxClasses().add(newClass.getKey());
             userTO.getResources().clear();
             userTO.getMemberships().clear();
             userTO.getDerAttrs().clear();
@@ -293,18 +299,18 @@ public class VirAttrITCase extends AbstractITCase {
 
             userTO.getDerAttrs().add(attrTO("csvuserid", null));
             userTO.getDerAttrs().add(attrTO("cn", null));
-            userTO.getVirAttrs().add(attrTO("virtualdata", "test@testone.org"));
+            userTO.getVirAttrs().add(attrTO(virSchema.getKey(), "test@testone.org"));
             // assign resource-csv to user
             userTO.getResources().add(RESOURCE_NAME_CSV);
             // save user
-            UserTO created = createUser(userTO);
+            userTO = createUser(userTO);
             // make std controls about user
-            assertNotNull(created);
-            assertTrue(RESOURCE_NAME_CSV.equals(created.getResources().iterator().next()));
-            assertEquals("test@testone.org", created.getVirAttrs().iterator().next().getValues().get(0));
+            assertNotNull(userTO);
+            assertTrue(RESOURCE_NAME_CSV.equals(userTO.getResources().iterator().next()));
+            assertEquals("test@testone.org", userTO.getVirAttrs().iterator().next().getValues().get(0));
 
             // update user
-            UserTO toBeUpdated = userService.read(created.getKey());
+            UserTO toBeUpdated = userService.read(userTO.getKey());
             UserPatch userPatch = new UserPatch();
             userPatch.setKey(toBeUpdated.getKey());
             userPatch.setPassword(new PasswordPatch.Builder().value("password234").build());
@@ -312,7 +318,7 @@ public class VirAttrITCase extends AbstractITCase {
             userPatch.getResources().add(new StringPatchItem.Builder().
                     operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_WS2).build());
             // modify virtual attribute
-            userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "test@testoneone.com"));
+            userPatch.getVirAttrs().add(attrTO(virSchema.getKey(), "test@testoneone.com"));
 
             // check Syncope change password
             userPatch.setPassword(new PasswordPatch.Builder().
@@ -348,15 +354,15 @@ public class VirAttrITCase extends AbstractITCase {
         userTO.getResources().add(RESOURCE_NAME_DBVIRATTR);
 
         // 1. create user
-        UserTO actual = createUser(userTO);
-        assertNotNull(actual);
+        userTO = createUser(userTO);
+        assertNotNull(userTO);
 
         // 2. check for virtual attribute value
-        actual = userService.read(actual.getKey());
-        assertEquals("virattrcache", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
+        userTO = userService.read(userTO.getKey());
+        assertEquals("virattrcache", userTO.getVirAttrMap().get("virtualdata").getValues().get(0));
 
         // ----------------------------------------
-        // 3. force cache expiring without any modification
+        // 3. change connector URL so that we are sure that any provided value will come from virtual cache
         // ----------------------------------------
         String jdbcURL = null;
         ConnInstanceTO connInstanceTO = connectorService.readByResource(
@@ -370,36 +376,29 @@ public class VirAttrITCase extends AbstractITCase {
         }
 
         connectorService.update(connInstanceTO);
-
-        UserPatch userPatch = new UserPatch();
-        userPatch.setKey(actual.getKey());
-        userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "virtualupdated"));
-
-        actual = updateUser(userPatch);
-        assertNotNull(actual);
         // ----------------------------------------
 
         // ----------------------------------------
-        // 4. update virtual attribute
+        // 4. update value on external resource
         // ----------------------------------------
-        final JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
+        JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
 
         String value = jdbcTemplate.queryForObject(
-                "SELECT USERNAME FROM testsync WHERE ID=?", String.class, actual.getKey());
+                "SELECT USERNAME FROM testsync WHERE ID=?", String.class, userTO.getKey());
         assertEquals("virattrcache", value);
 
-        jdbcTemplate.update("UPDATE testsync set USERNAME='virattrcache2' WHERE ID=?", actual.getKey());
+        jdbcTemplate.update("UPDATE testsync set USERNAME='virattrcache2' WHERE ID=?", userTO.getKey());
 
         value = jdbcTemplate.queryForObject(
-                "SELECT USERNAME FROM testsync WHERE ID=?", String.class, actual.getKey());
+                "SELECT USERNAME FROM testsync WHERE ID=?", String.class, userTO.getKey());
         assertEquals("virattrcache2", value);
         // ----------------------------------------
 
-        actual = userService.read(actual.getKey());
-        assertEquals("virattrcache", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
+        userTO = userService.read(userTO.getKey());
+        assertEquals("virattrcache", userTO.getVirAttrMap().get("virtualdata").getValues().get(0));
 
         // ----------------------------------------
-        // 5. restore connector
+        // 5. restore connector URL, values can be read again from external resource
         // ----------------------------------------
         for (ConnConfProperty prop : connInstanceTO.getConfiguration()) {
             if ("jdbcUrlTemplate".equals(prop.getSchema().getName())) {
@@ -411,8 +410,20 @@ public class VirAttrITCase extends AbstractITCase {
         connectorService.update(connInstanceTO);
         // ----------------------------------------
 
-        actual = userService.read(actual.getKey());
-        assertEquals("virattrcache2", actual.getVirAttrMap().get("virtualdata").getValues().get(0));
+        // cached value still in place...
+        userTO = userService.read(userTO.getKey());
+        assertEquals("virattrcache", userTO.getVirAttrMap().get("virtualdata").getValues().get(0));
+
+        // force cache update by adding a resource which has virtualdata mapped for propagation
+        UserPatch userPatch = new UserPatch();
+        userPatch.setKey(userTO.getKey());
+        userPatch.getResources().add(new StringPatchItem.Builder().
+                operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_WS2).build());
+        userTO = updateUser(userPatch);
+        assertNotNull(userTO);
+
+        userTO = userService.read(userTO.getKey());
+        assertEquals("virattrcache2", userTO.getVirAttrMap().get("virtualdata").getValues().get(0));
     }
 
     @Test
@@ -423,7 +434,7 @@ public class VirAttrITCase extends AbstractITCase {
         userTO.getResources().add(RESOURCE_NAME_LDAP);
         userTO.getVirAttrs().add(attrTO("virtualReadOnly", "readOnly"));
         userTO = createUser(userTO);
-        //Finding no values because the virtual attribute is readonly 
+        // finding no values because the virtual attribute is readonly 
         assertTrue(userTO.getVirAttrMap().get("virtualReadOnly").getValues().isEmpty());
     }
 
@@ -527,27 +538,13 @@ public class VirAttrITCase extends AbstractITCase {
     public void issueSYNCOPE459() {
         UserTO userTO = UserITCase.getUniqueSampleTO("syncope459@apache.org");
         userTO.getResources().clear();
+        userTO.getResources().add(RESOURCE_NAME_LDAP);
         userTO.getMemberships().clear();
         userTO.getVirAttrs().clear();
 
-        AttrTO virtualReadOnly = attrTO("virtualReadOnly", "");
-        virtualReadOnly.getValues().clear();
-
-        userTO.getVirAttrs().add(virtualReadOnly);
-
         userTO = createUser(userTO);
 
         assertNotNull(userTO.getVirAttrMap().get("virtualReadOnly"));
-
-        UserPatch userPatch = new UserPatch();
-        userPatch.setKey(userTO.getKey());
-        userPatch.getVirAttrs().add(new AttrPatch.Builder().
-                operation(PatchOperation.ADD_REPLACE).
-                attrTO(new AttrTO.Builder().schema("virtualdata").build()).
-                build());
-
-        userTO = updateUser(userPatch);
-        assertNotNull(userTO.getVirAttrMap().get("virtualdata"));
     }
 
     @Test
@@ -572,7 +569,7 @@ public class VirAttrITCase extends AbstractITCase {
         UserPatch userPatch = new UserPatch();
         userPatch.setKey(userTO.getKey());
         // change virtual attribute value
-        userPatch.getVirAttrs().add(attrAddReplacePatch("virtualdata", "syncope501_updated@apache.org"));
+        userPatch.getVirAttrs().add(attrTO("virtualdata", "syncope501_updated@apache.org"));
 
         userTO = updateUser(userPatch);
         assertNotNull(userTO);
@@ -584,80 +581,76 @@ public class VirAttrITCase extends AbstractITCase {
 
     @Test
     public void issueSYNCOPE691() {
-        final String res = RESOURCE_NAME_LDAP + "691";
-
         ResourceTO ldap = resourceService.read(RESOURCE_NAME_LDAP);
-        ldap.setKey(res);
-
         try {
+            ProvisionTO provision = ldap.getProvision(AnyTypeKind.USER.name());
+            assertNotNull(provision);
+            CollectionUtils.filterInverse(provision.getMapping().getItems(), new Predicate<MappingItemTO>() {
 
-            CollectionUtils.filterInverse(ldap.getProvision(AnyTypeKind.USER.name()).getMapping().getItems(),
-                    new Predicate<MappingItemTO>() {
-
-                        @Override
-                        public boolean evaluate(final MappingItemTO item) {
-                            return "mail".equals(item.getExtAttrName());
-                        }
-                    });
-
-            final MappingItemTO mail = new MappingItemTO();
-            // unset internal attribute mail and set virtual attribute virtualdata as mapped to external email
-            mail.setIntMappingType(IntMappingType.UserVirtualSchema);
-            mail.setIntAttrName("virtualdata");
-            mail.setPurpose(MappingPurpose.BOTH);
-            mail.setExtAttrName("mail");
-
-            ldap.getProvision(AnyTypeKind.USER.name()).getMapping().getItems().add(mail);
+                @Override
+                public boolean evaluate(final MappingItemTO item) {
+                    return "mail".equals(item.getExtAttrName());
+                }
+            });
+            provision.getVirSchemas().clear();
 
+            ldap.setKey(RESOURCE_NAME_LDAP + "691" + getUUIDString());
             resourceService.create(ldap);
 
-            ldap = resourceService.read(res);
-            assertNotNull(ldap.getProvision(AnyTypeKind.USER.name()).getMapping());
-
-            assertTrue(CollectionUtils.exists(ldap.getProvision(AnyTypeKind.USER.name()).getMapping().getItems(),
-                    new Predicate<MappingItemTO>() {
-
-                        @Override
-                        public boolean evaluate(final MappingItemTO item) {
-                            return "mail".equals(item.getExtAttrName()) && "virtualdata".equals(item.getIntAttrName());
-                        }
-                    }));
+            ldap = resourceService.read(ldap.getKey());
+            provision = ldap.getProvision(AnyTypeKind.USER.name());
+            assertNotNull(provision);
+
+            // create new virtual schema for the resource below
+            VirSchemaTO virSchema = new VirSchemaTO();
+            virSchema.setKey("syncope691" + getUUIDString());
+            virSchema.setExtAttrName("mail");
+            virSchema.setProvision(provision.getKey());
+            virSchema = createSchema(SchemaType.VIRTUAL, virSchema);
+            assertNotNull(virSchema);
+
+            AnyTypeClassTO newClass = new AnyTypeClassTO();
+            newClass.setKey("syncope691" + getUUIDString());
+            newClass.getVirSchemas().add(virSchema.getKey());
+            Response response = anyTypeClassService.create(newClass);
+            assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatusInfo().getStatusCode());
+            newClass = getObject(response.getLocation(), AnyTypeClassService.class, AnyTypeClassTO.class);
 
             // create a new user
             UserTO userTO = UserITCase.getUniqueSampleTO("syncope691@syncope.apache.org");
+            userTO.getAuxClasses().add(newClass.getKey());
             userTO.getResources().clear();
             userTO.getMemberships().clear();
             userTO.getDerAttrs().clear();
             userTO.getVirAttrs().clear();
 
-            final AttrTO emailTO = new AttrTO();
-            emailTO.setSchema("virtualdata");
+            AttrTO emailTO = new AttrTO();
+            emailTO.setSchema(virSchema.getKey());
             emailTO.getValues().add("test@issue691.dom1.org");
             emailTO.getValues().add("test@issue691.dom2.org");
 
             userTO.getVirAttrs().add(emailTO);
             // assign resource-ldap691 to user
-            userTO.getResources().add(res);
+            userTO.getResources().add(ldap.getKey());
             // save user
-            UserTO created = createUser(userTO);
+            userTO = createUser(userTO);
             // make std controls about user
-            assertNotNull(created);
-            assertTrue(res.equals(created.getResources().iterator().next()));
+            assertNotNull(userTO);
+            assertTrue(ldap.getKey().equals(userTO.getResources().iterator().next()));
 
-            assertEquals(2, created.getVirAttrs().iterator().next().getValues().size(), 0);
-            assertTrue(created.getVirAttrs().iterator().next().getValues().contains("test@issue691.dom1.org"));
-            assertTrue(created.getVirAttrs().iterator().next().getValues().contains("test@issue691.dom2.org"));
+            assertEquals(2, userTO.getVirAttrs().iterator().next().getValues().size(), 0);
+            assertTrue(userTO.getVirAttrs().iterator().next().getValues().contains("test@issue691.dom1.org"));
+            assertTrue(userTO.getVirAttrs().iterator().next().getValues().contains("test@issue691.dom2.org"));
 
             // update user
             UserPatch userPatch = new UserPatch();
-            userPatch.setKey(created.getKey());
+            userPatch.setKey(userTO.getKey());
             // modify virtual attribute
-            userPatch.getVirAttrs().add(new AttrPatch.Builder().
-                    operation(PatchOperation.ADD_REPLACE).
-                    attrTO(new AttrTO.Builder().schema("virtualdata").
-                            value("test@issue691.dom3.org").
-                            value("test@issue691.dom4.org").
-                            build()).build());
+            userPatch.getVirAttrs().add(
+                    new AttrTO.Builder().schema(virSchema.getKey()).
+                    value("test@issue691.dom3.org").
+                    value("test@issue691.dom4.org").
+                    build());
 
             UserTO updated = updateUser(userPatch);
             assertNotNull(updated);
@@ -666,7 +659,7 @@ public class VirAttrITCase extends AbstractITCase {
             assertTrue(updated.getVirAttrs().iterator().next().getValues().contains("test@issue691.dom4.org"));
         } finally {
             try {
-                resourceService.delete(res);
+                resourceService.delete(ldap.getKey());
             } catch (Exception ignore) {
                 // ignore
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirSchemaITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirSchemaITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirSchemaITCase.java
index a1ee34d..caae156 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirSchemaITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirSchemaITCase.java
@@ -27,6 +27,7 @@ import static org.junit.Assert.fail;
 import java.util.List;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.to.VirSchemaTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.EntityViolationType;
@@ -48,41 +49,47 @@ public class VirSchemaITCase extends AbstractITCase {
     }
 
     @Test
-    public void read() {
-        VirSchemaTO vSchemaTO = schemaService.read(SchemaType.VIRTUAL, "mvirtualdata");
-        assertNotNull(vSchemaTO);
-    }
+    public void crud() {
+        ResourceTO csv = resourceService.read(RESOURCE_NAME_CSV);
+        assertNotNull(csv);
+        assertEquals(1, csv.getProvisions().size());
+        assertTrue(csv.getProvisions().get(0).getVirSchemas().isEmpty());
 
-    @Test
-    public void create() {
         VirSchemaTO schema = new VirSchemaTO();
-        schema.setKey("virtual");
+        schema.setKey("virtualTest" + getUUIDString());
+        schema.setExtAttrName("name");
+        schema.setProvision(csv.getProvisions().get(0).getKey());
 
-        VirSchemaTO actual = createSchema(SchemaType.VIRTUAL, schema);
-        assertNotNull(actual);
+        schema = createSchema(SchemaType.VIRTUAL, schema);
+        assertNotNull(schema);
+        assertEquals(csv.getProvisions().get(0).getKey(), schema.getProvision());
 
-        actual = schemaService.read(SchemaType.VIRTUAL, actual.getKey());
-        assertNotNull(actual);
-    }
+        csv = resourceService.read(RESOURCE_NAME_CSV);
+        assertNotNull(csv);
+        assertEquals(1, csv.getProvisions().size());
+        assertFalse(csv.getProvisions().get(0).getVirSchemas().isEmpty());
 
-    @Test
-    public void delete() {
-        VirSchemaTO schema = schemaService.read(SchemaType.VIRTUAL, "rvirtualdata");
+        schema = schemaService.read(SchemaType.VIRTUAL, schema.getKey());
         assertNotNull(schema);
 
         schemaService.delete(SchemaType.VIRTUAL, schema.getKey());
 
         try {
-            schemaService.read(SchemaType.VIRTUAL, "rvirtualdata");
+            schemaService.read(SchemaType.VIRTUAL, schema.getKey());
             fail();
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.NotFound, e.getType());
         }
+
+        csv = resourceService.read(RESOURCE_NAME_CSV);
+        assertNotNull(csv);
+        assertEquals(1, csv.getProvisions().size());
+        assertTrue(csv.getProvisions().get(0).getVirSchemas().isEmpty());
     }
 
     @Test
     public void issueSYNCOPE323() {
-        VirSchemaTO actual = schemaService.read(SchemaType.VIRTUAL, "mvirtualdata");
+        VirSchemaTO actual = schemaService.read(SchemaType.VIRTUAL, "virtualdata");
         assertNotNull(actual);
 
         try {


[42/54] [abbrv] syncope git commit: [SYNCOPE-709] Refactoring completed

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
index 3d60089..5763449 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.core.provisioning.java;
 
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -27,26 +26,12 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Predicate;
+import org.apache.commons.collections4.ListUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.lib.patch.AttrPatch;
-import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.IntMappingType;
-import org.apache.syncope.common.lib.types.PropagationByResource;
-import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.core.misc.MappingUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
-import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
-import org.apache.syncope.core.persistence.api.dao.VirAttrDAO;
-import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.AnyUtils;
-import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
@@ -68,30 +53,17 @@ import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
 @Component
-@Transactional(rollbackFor = { Throwable.class })
 public class VirAttrHandlerImpl implements VirAttrHandler {
 
     private static final Logger LOG = LoggerFactory.getLogger(VirAttrHandler.class);
 
     @Autowired
-    private VirSchemaDAO virSchemaDAO;
-
-    @Autowired
-    private VirAttrDAO virAttrDAO;
-
-    @Autowired
     private AnyObjectDAO anyObjectDAO;
 
     @Autowired
     private UserDAO userDAO;
 
     @Autowired
-    private GroupDAO groupDAO;
-
-    @Autowired
-    private AnyUtilsFactory anyUtilsFactory;
-
-    @Autowired
     private ConnectorFactory connFactory;
 
     /**
@@ -103,290 +75,102 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
     @Autowired
     private MappingUtils mappingUtils;
 
-    @Override
-    public VirSchema getVirSchema(final String virSchemaName) {
-        VirSchema virtualSchema = null;
-        if (StringUtils.isNotBlank(virSchemaName)) {
-            virtualSchema = virSchemaDAO.find(virSchemaName);
-
-            if (virtualSchema == null) {
-                LOG.debug("Ignoring invalid virtual schema {}", virSchemaName);
-            }
+    private Map<VirSchema, List<String>> getValues(final Any<?, ?> any, final Set<VirSchema> schemas) {
+        Collection<? extends ExternalResource> ownedResources;
+        if (any instanceof User) {
+            ownedResources = userDAO.findAllResources((User) any);
+        } else if (any instanceof AnyObject) {
+            ownedResources = anyObjectDAO.findAllResources((AnyObject) any);
+        } else {
+            ownedResources = ((Group) any).getResources();
         }
 
-        return virtualSchema;
-    }
-
-    @Override
-    public void updateOnResourcesIfMappingMatches(final Any<?, ?, ?> any, final String schemaKey,
-            final Iterable<? extends ExternalResource> resources, final IntMappingType mappingType,
-            final PropagationByResource propByRes) {
+        Map<VirSchema, List<String>> result = new HashMap<>();
 
-        for (ExternalResource resource : resources) {
-            for (MappingItem mapItem
-                    : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
+        Map<Provision, Set<VirSchema>> toRead = new HashMap<>();
 
-                if (schemaKey.equals(mapItem.getIntAttrName()) && mapItem.getIntMappingType() == mappingType) {
-                    propByRes.add(ResourceOperation.UPDATE, resource.getKey());
-                }
-            }
-        }
-    }
-
-    private Iterable<? extends ExternalResource> getAllResources(final Any<?, ?, ?> any) {
-        return any instanceof User
-                ? userDAO.findAllResources((User) any)
-                : any instanceof AnyObject
-                        ? anyObjectDAO.findAllResources((AnyObject) any)
-                        : any instanceof Group
-                                ? ((Group) any).getResources()
-                                : Collections.<ExternalResource>emptySet();
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    public void createVirtual(final Any any, final Collection<AttrTO> vAttrs) {
-        AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
+        for (VirSchema schema : schemas) {
+            if (ownedResources.contains(schema.getProvision().getResource())) {
+                VirAttrCacheValue virAttrCacheValue =
+                        virAttrCache.get(any.getType().getKey(), any.getKey(), schema.getKey());
 
-        for (AttrTO attrTO : vAttrs) {
-            VirAttr virAttr = any.getVirAttr(attrTO.getSchema());
-            if (virAttr == null) {
-                VirSchema virSchema = getVirSchema(attrTO.getSchema());
-                if (virSchema != null) {
-                    virAttr = anyUtils.newVirAttr();
-                    virAttr.setSchema(virSchema);
-                    if (virAttr.getSchema() == null) {
-                        LOG.debug("Ignoring {} because no valid schema was found", attrTO);
-                    } else {
-                        virAttr.setOwner(any);
-                        any.add(virAttr);
-                        virAttr.getValues().clear();
-                        virAttr.getValues().addAll(attrTO.getValues());
+                if (virAttrCache.isValidEntry(virAttrCacheValue)) {
+                    LOG.debug("Values for {} found in cache: {}", schema, virAttrCacheValue);
+                    result.put(schema, virAttrCacheValue.getValues());
+                } else {
+                    Set<VirSchema> schemasToRead = toRead.get(schema.getProvision());
+                    if (schemasToRead == null) {
+                        schemasToRead = new HashSet<>();
+                        toRead.put(schema.getProvision(), schemasToRead);
                     }
+                    schemasToRead.add(schema);
                 }
             } else {
-                virAttr.getValues().clear();
-                virAttr.getValues().addAll(attrTO.getValues());
+                LOG.debug("Not considering {} since {} is not assigned to {}",
+                        schema, any, schema.getProvision().getResource());
             }
         }
-    }
-
-    private Any<?, ?, ?> find(final Long key, final AnyTypeKind anyTypeKind) {
-        Any<?, ?, ?> result;
-
-        switch (anyTypeKind) {
-            case USER:
-                result = userDAO.authFind(key);
-                break;
-
-            case GROUP:
-                result = groupDAO.authFind(key);
-                break;
-
-            case ANY_OBJECT:
-            default:
-                result = anyObjectDAO.authFind(key);
-        }
-
-        return result;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    public PropagationByResource updateVirtual(final Any any, final Collection<AttrPatch> vAttrs) {
-        AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
-
-        PropagationByResource propByRes = new PropagationByResource();
-
-        Iterable<? extends ExternalResource> externalResources = getAllResources(any);
-
-        for (AttrPatch patch : vAttrs) {
-            VirSchema virSchema = getVirSchema(patch.getAttrTO().getSchema());
-            if (virSchema != null) {
-                VirAttr virAttr = any.getVirAttr(virSchema.getKey());
-                switch (patch.getOperation()) {
-                    case ADD_REPLACE:
-                        if (virAttr == null) {
-                            virAttr = anyUtils.newVirAttr();
-                            virAttr.setOwner(any);
-                            virAttr.setSchema(virSchema);
-
-                            any.add(virAttr);
-                        }
-
-                        updateOnResourcesIfMappingMatches(
-                                any, virSchema.getKey(), externalResources, anyUtils.virIntMappingType(), propByRes);
-
-                        if (!virAttr.getValues().equals(patch.getAttrTO().getValues())) {
-                            virAttr.getValues().clear();
-                            virAttr.getValues().addAll(patch.getAttrTO().getValues());
-                        }
-                        break;
-
-                    case DELETE:
-                    default:
-                        if (virAttr == null) {
-                            LOG.debug("No virtual attribute found for schema {}", virSchema.getKey());
-                        } else {
-                            any.remove(virAttr);
-                            virAttrDAO.delete(virAttr);
-                        }
-
-                        for (ExternalResource resource : externalResources) {
-                            for (MappingItem mapItem
-                                    : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
 
-                                if (virSchema.getKey().equals(mapItem.getIntAttrName())
-                                        && mapItem.getIntMappingType() == anyUtils.virIntMappingType()) {
+        for (Map.Entry<Provision, Set<VirSchema>> entry : toRead.entrySet()) {
+            LOG.debug("About to read from {}: {}", entry.getKey(), entry.getValue());
 
-                                    propByRes.add(ResourceOperation.UPDATE, resource.getKey());
-
-                                    // Using virtual attribute as ConnObjectKey must be avoided
-                                    if (mapItem.isConnObjectKey()
-                                            && virAttr != null && !virAttr.getValues().isEmpty()) {
-
-                                        propByRes.addOldConnObjectKey(
-                                                resource.getKey(), virAttr.getValues().get(0).toString());
-                                    }
-                                }
-                            }
-                        }
+            String connObjectKey = MappingUtils.getConnObjectKeyItem(entry.getKey()) == null
+                    ? null
+                    : mappingUtils.getConnObjectKeyValue(any, entry.getKey());
+            if (StringUtils.isBlank(connObjectKey)) {
+                LOG.error("No ConnObjectKey found for {}, ignoring...", entry.getKey());
+            } else {
+                Set<MappingItem> linkingMappingItems = new HashSet<>();
+                for (VirSchema schema : entry.getValue()) {
+                    linkingMappingItems.add(schema.asLinkingMappingItem());
                 }
-            }
-        }
-
-        return propByRes;
-    }
-
-    @Transactional
-    @Override
-    public PropagationByResource updateVirtual(
-            final Long key, final AnyTypeKind anyTypeKind, final Collection<AttrPatch> vAttrs) {
-
-        return updateVirtual(find(key, anyTypeKind), vAttrs);
-    }
-
-    @Override
-    public void retrieveVirAttrValues(final Any<?, ?, ?> any) {
-        IntMappingType type = any.getType().getKind() == AnyTypeKind.USER
-                ? IntMappingType.UserVirtualSchema
-                : any.getType().getKind() == AnyTypeKind.GROUP
-                        ? IntMappingType.GroupVirtualSchema
-                        : IntMappingType.AnyObjectVirtualSchema;
-
-        Map<String, ConnectorObject> resources = new HashMap<>();
-
-        // -----------------------
-        // Retrieve virtual attribute values if and only if they have not been retrieved yet
-        // -----------------------
-        for (VirAttr<?> virAttr : any.getVirAttrs()) {
-            // reset value set
-            if (virAttr.getValues().isEmpty()) {
-                retrieveVirAttrValue(any, virAttr, type, resources);
-            }
-        }
-        // -----------------------
-    }
-
-    private void retrieveVirAttrValue(
-            final Any<?, ?, ?> any,
-            final VirAttr<?> virAttr,
-            final IntMappingType type,
-            final Map<String, ConnectorObject> externalResources) {
-
-        String schemaName = virAttr.getSchema().getKey();
-        VirAttrCacheValue virAttrCacheValue = virAttrCache.get(any.getType().getKey(), any.getKey(), schemaName);
-
-        LOG.debug("Retrieve values for virtual attribute {} ({})", schemaName, type);
-
-        if (virAttrCache.isValidEntry(virAttrCacheValue)) {
-            // cached ...
-            LOG.debug("Values found in cache {}", virAttrCacheValue);
-            virAttr.getValues().clear();
-            virAttr.getValues().addAll(new ArrayList<>(virAttrCacheValue.getValues()));
-        } else {
-            // not cached ...
-            LOG.debug("Need one or more remote connections");
-
-            VirAttrCacheValue toBeCached = new VirAttrCacheValue();
-
-            for (ExternalResource resource : getTargetResources(virAttr, type, any.getType())) {
-                Provision provision = resource.getProvision(any.getType());
-                LOG.debug("Search values into {},{}", resource, provision);
 
+                Connector connector = connFactory.getConnector(entry.getKey().getResource());
                 try {
-                    List<MappingItem> mapItems = MappingUtils.getBothMappingItems(provision);
+                    ConnectorObject connectorObject = connector.getObject(
+                            entry.getKey().getObjectClass(),
+                            new Uid(connObjectKey),
+                            connector.getOperationOptions(linkingMappingItems.iterator()));
 
-                    ConnectorObject connectorObject;
-                    if (externalResources.containsKey(resource.getKey())) {
-                        connectorObject = externalResources.get(resource.getKey());
+                    if (connectorObject == null) {
+                        LOG.debug("No read from {} about {}", entry.getKey(), connObjectKey);
                     } else {
-                        LOG.debug("Perform connection to {}", resource.getKey());
-                        String connObjectKey = MappingUtils.getConnObjectKeyItem(provision) == null
-                                ? null
-                                : mappingUtils.getConnObjectKeyValue(any, provision);
-
-                        if (StringUtils.isBlank(connObjectKey)) {
-                            throw new IllegalArgumentException("No ConnObjectKey found for " + resource.getKey());
-                        }
-
-                        Connector connector = connFactory.getConnector(resource);
-                        connectorObject = connector.getObject(
-                                provision.getObjectClass(),
-                                new Uid(connObjectKey),
-                                connector.getOperationOptions(MappingUtils.getMatchingMappingItems(mapItems, type)));
-                        externalResources.put(resource.getKey(), connectorObject);
-                    }
-
-                    if (connectorObject != null) {
-                        // the same virtual attribute could be mapped with one or more external attributes
-                        for (MappingItem mapItem : MappingUtils.getMatchingMappingItems(mapItems, schemaName, type)) {
-                            Attribute attr = connectorObject.getAttributeByName(mapItem.getExtAttrName());
-                            if (attr != null && attr.getValue() != null) {
-                                for (Object obj : attr.getValue()) {
-                                    if (obj != null) {
-                                        virAttr.getValues().add(obj.toString());
-                                    }
-                                }
+                        for (VirSchema schema : entry.getValue()) {
+                            Attribute attr = connectorObject.getAttributeByName(schema.getExtAttrName());
+                            if (attr != null) {
+                                VirAttrCacheValue virAttrCacheValue = new VirAttrCacheValue();
+                                virAttrCacheValue.setValues(attr.getValue());
+                                virAttrCache.put(any.getType().getKey(), any.getKey(), schema.getKey(),
+                                        virAttrCacheValue);
+                                LOG.debug("Values for {} set in cache: {}", schema, virAttrCacheValue);
+
+                                result.put(schema, virAttrCacheValue.getValues());
                             }
                         }
-
-                        toBeCached.setResourceValues(resource.getKey(), new HashSet<>(virAttr.getValues()));
-
-                        LOG.debug("Retrieved values {}", virAttr.getValues());
                     }
                 } catch (Exception e) {
-                    LOG.error("Error reading connector object from {}", resource.getKey(), e);
-
-                    if (virAttrCacheValue != null) {
-                        toBeCached.forceExpiring();
-                        LOG.debug("Search for a cached value (even expired!) ...");
-                        final Set<String> cachedValues = virAttrCacheValue.getValues(resource.getKey());
-                        if (cachedValues != null) {
-                            LOG.debug("Use cached value {}", cachedValues);
-                            virAttr.getValues().addAll(cachedValues);
-                            toBeCached.setResourceValues(resource.getKey(), new HashSet<>(cachedValues));
-                        }
-                    }
+                    LOG.error("Error reading from {}", entry.getKey(), e);
                 }
             }
-
-            virAttrCache.put(any.getType().getKey(), any.getKey(), schemaName, toBeCached);
         }
+
+        return result;
     }
 
-    private Collection<ExternalResource> getTargetResources(
-            final VirAttr<?> attr, final IntMappingType type, final AnyType anyType) {
+    @Transactional(readOnly = true)
+    @Override
+    public List<String> getValues(final Any<?, ?> any, final VirSchema schema) {
+        if (!any.getAllowedVirSchemas().contains(schema)) {
+            LOG.debug("{} not allowed for {}", schema, any);
+            return Collections.emptyList();
+        }
 
-        return CollectionUtils.select(getAllResources(attr.getOwner()), new Predicate<ExternalResource>() {
+        return ListUtils.emptyIfNull(getValues(any, Collections.singleton(schema)).get(schema));
+    }
 
-            @Override
-            public boolean evaluate(final ExternalResource resource) {
-                return resource.getProvision(anyType) != null
-                        && !MappingUtils.getMatchingMappingItems(
-                                MappingUtils.getBothMappingItems(resource.getProvision(anyType)),
-                                attr.getSchema().getKey(), type).isEmpty();
-            }
-        });
+    @Transactional(readOnly = true)
+    @Override
+    public Map<VirSchema, List<String>> getValues(final Any<?, ?> any) {
+        return getValues(any, any.getAllowedVirSchemas());
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index 4a203f9..93a0b31 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -42,6 +42,7 @@ import org.apache.syncope.common.lib.to.RelationshipTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
 import org.apache.syncope.core.persistence.api.dao.DerAttrDAO;
@@ -53,7 +54,6 @@ import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
-import org.apache.syncope.core.persistence.api.dao.VirAttrDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.DerAttr;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
@@ -61,8 +61,6 @@ import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
-import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.core.misc.ConnObjectUtils;
@@ -80,6 +78,7 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Relationship;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
@@ -130,9 +129,6 @@ abstract class AbstractAnyDataBinder {
     protected DerAttrDAO derAttrDAO;
 
     @Autowired
-    protected VirAttrDAO virAttrDAO;
-
-    @Autowired
     protected PlainAttrValueDAO plainAttrValueDAO;
 
     @Autowired
@@ -159,7 +155,7 @@ abstract class AbstractAnyDataBinder {
     @Autowired
     protected MappingUtils mappingUtils;
 
-    protected void setRealm(final Any<?, ?, ?> any, final AnyPatch anyPatch) {
+    protected void setRealm(final Any<?, ?> any, final AnyPatch anyPatch) {
         if (anyPatch.getRealm() != null && StringUtils.isNotBlank(anyPatch.getRealm().getValue())) {
             Realm newRealm = realmDAO.find(anyPatch.getRealm().getValue());
             if (newRealm == null) {
@@ -225,7 +221,7 @@ abstract class AbstractAnyDataBinder {
         }
     }
 
-    private List<String> evaluateMandatoryCondition(final Provision provision, final Any<?, ?, ?> any) {
+    private List<String> evaluateMandatoryCondition(final Provision provision, final Any<?, ?> any) {
         List<String> missingAttrNames = new ArrayList<>();
 
         if (provision != null) {
@@ -235,7 +231,7 @@ abstract class AbstractAnyDataBinder {
                         || item.getPurpose() == MappingPurpose.BOTH)) {
 
                     List<PlainAttrValue> values = mappingUtils.getIntValues(
-                            provision, item, Collections.<Any<?, ?, ?>>singletonList(any), null);
+                            provision, item, Collections.<Any<?, ?>>singletonList(any));
                     if (values.isEmpty() && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) {
                         missingAttrNames.add(item.getIntAttrName());
                     }
@@ -247,7 +243,7 @@ abstract class AbstractAnyDataBinder {
     }
 
     private SyncopeClientException checkMandatoryOnResources(
-            final Any<?, ?, ?> any, final Set<ExternalResource> resources) {
+            final Any<?, ?> any, final Set<ExternalResource> resources) {
 
         SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
 
@@ -266,7 +262,7 @@ abstract class AbstractAnyDataBinder {
         return reqValMissing;
     }
 
-    private SyncopeClientException checkMandatory(final Any<?, ?, ?> any) {
+    private SyncopeClientException checkMandatory(final Any<?, ?> any) {
         SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
 
         // Check if there is some mandatory schema defined for which no value has been provided
@@ -284,7 +280,7 @@ abstract class AbstractAnyDataBinder {
         return reqValMissing;
     }
 
-    private Set<ExternalResource> getAllResources(final Any<?, ?, ?> any) {
+    private Set<ExternalResource> getAllResources(final Any<?, ?> any) {
         Set<ExternalResource> resources = new HashSet<>();
 
         if (any instanceof User) {
@@ -323,21 +319,26 @@ abstract class AbstractAnyDataBinder {
 
         switch (patch.getOperation()) {
             case ADD_REPLACE:
-                virAttrHander.updateOnResourcesIfMappingMatches(
-                        any, schema.getKey(), resources, anyUtils.plainIntMappingType(), propByRes);
-
                 // 1.1 remove values
-                Collection<Long> valuesToBeRemoved = attr.getSchema().isUniqueConstraint()
-                        ? Collections.singleton(attr.getUniqueValue().getKey())
-                        : CollectionUtils.collect(attr.getValues(), new Transformer<PlainAttrValue, Long>() {
-
-                            @Override
-                            public Long transform(final PlainAttrValue input) {
-                                return input.getKey();
-                            }
-                        });
-                for (Long attrValueKey : valuesToBeRemoved) {
-                    plainAttrValueDAO.delete(attrValueKey, anyUtils.plainAttrValueClass());
+                if (attr.getSchema().isUniqueConstraint()) {
+                    if (attr.getUniqueValue() != null
+                            && !patch.getAttrTO().getValues().isEmpty()
+                            && !patch.getAttrTO().getValues().get(0).equals(attr.getUniqueValue().getValueAsString())) {
+
+                        plainAttrValueDAO.delete(attr.getUniqueValue().getKey(), anyUtils.plainAttrUniqueValueClass());
+                    }
+                } else {
+                    Collection<Long> valuesToBeRemoved = CollectionUtils.collect(attr.getValues(),
+                            new Transformer<PlainAttrValue, Long>() {
+
+                                @Override
+                                public Long transform(final PlainAttrValue input) {
+                                    return input.getKey();
+                                }
+                            });
+                    for (Long attrValueKey : valuesToBeRemoved) {
+                        plainAttrValueDAO.delete(attrValueKey, anyUtils.plainAttrValueClass());
+                    }
                 }
 
                 // 1.2 add values
@@ -359,22 +360,20 @@ abstract class AbstractAnyDataBinder {
             default:
                 any.remove(attr);
                 plainAttrDAO.delete(attr.getKey(), anyUtils.plainAttrClass());
+        }
 
-                for (ExternalResource resource : resources) {
-                    for (MappingItem mapItem
-                            : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
-
-                        if (schema.getKey().equals(mapItem.getIntAttrName())
-                                && mapItem.getIntMappingType() == anyUtils.plainIntMappingType()) {
+        for (ExternalResource resource : resources) {
+            for (MappingItem mapItem : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
+                if (schema.getKey().equals(mapItem.getIntAttrName())
+                        && mapItem.getIntMappingType() == anyUtils.plainIntMappingType()) {
 
-                            propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+                    propByRes.add(ResourceOperation.UPDATE, resource.getKey());
 
-                            if (mapItem.isConnObjectKey() && !attr.getValuesAsStrings().isEmpty()) {
-                                propByRes.addOldConnObjectKey(resource.getKey(), attr.getValuesAsStrings().get(0));
-                            }
-                        }
+                    if (mapItem.isConnObjectKey() && !attr.getValuesAsStrings().isEmpty()) {
+                        propByRes.addOldConnObjectKey(resource.getKey(), attr.getValuesAsStrings().get(0));
                     }
                 }
+            }
         }
     }
 
@@ -400,36 +399,26 @@ abstract class AbstractAnyDataBinder {
             }
         }
 
-        switch (patch.getOperation()) {
-            case ADD_REPLACE:
-                virAttrHander.updateOnResourcesIfMappingMatches(
-                        any, schema.getKey(), resources, anyUtils.derIntMappingType(), propByRes);
-                break;
-
-            case DELETE:
-            default:
-                derAttrDAO.delete(attr);
-
-                for (ExternalResource resource : resources) {
-                    for (MappingItem mapItem
-                            : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
+        if (patch.getOperation() == PatchOperation.DELETE) {
+            derAttrDAO.delete(attr);
+        }
 
-                        if (schema.getKey().equals(mapItem.getIntAttrName())
-                                && mapItem.getIntMappingType() == anyUtils.derIntMappingType()) {
+        for (ExternalResource resource : resources) {
+            for (MappingItem mapItem : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
+                if (schema.getKey().equals(mapItem.getIntAttrName())
+                        && mapItem.getIntMappingType() == anyUtils.derIntMappingType()) {
 
-                            propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+                    propByRes.add(ResourceOperation.UPDATE, resource.getKey());
 
-                            if (mapItem.isConnObjectKey() && !attr.getValue(any.getPlainAttrs()).isEmpty()) {
-                                propByRes.addOldConnObjectKey(resource.getKey(), attr.getValue(any.getPlainAttrs()));
-                            }
-                        }
+                    if (mapItem.isConnObjectKey() && !attr.getValue(any.getPlainAttrs()).isEmpty()) {
+                        propByRes.addOldConnObjectKey(resource.getKey(), attr.getValue(any.getPlainAttrs()));
                     }
                 }
+            }
         }
     }
 
-    @SuppressWarnings("rawtypes")
-    protected PropagationByResource fill(final Any any, final AnyPatch anyPatch, final AnyUtils anyUtils,
+    protected PropagationByResource fill(final Any<?, ?> any, final AnyPatch anyPatch, final AnyUtils anyUtils,
             final SyncopeClientCompositeException scce) {
 
         PropagationByResource propByRes = new PropagationByResource();
@@ -576,25 +565,12 @@ abstract class AbstractAnyDataBinder {
             }
         }
 
-        // 3. virtual attributes
-        for (AttrTO vattrTO : anyTO.getVirAttrs()) {
-            VirSchema virSchema = virAttrHander.getVirSchema(vattrTO.getSchema());
-            if (virSchema != null) {
-                VirAttr virAttr = anyUtils.newVirAttr();
-                virAttr.setOwner(any);
-                virAttr.setSchema(virSchema);
-                any.add(virAttr);
-            }
-        }
-
         SyncopeClientException requiredValuesMissing = checkMandatory(any);
         if (!requiredValuesMissing.isEmpty()) {
             scce.addException(requiredValuesMissing);
         }
 
-        virAttrHander.createVirtual(any, anyTO.getVirAttrs());
-
-        // 4. realm & resources
+        // 3. realm & resources
         Realm realm = realmDAO.find(anyTO.getRealm());
         if (realm == null) {
             SyncopeClientException noRealm = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
@@ -628,7 +604,7 @@ abstract class AbstractAnyDataBinder {
             final Collection<? extends AnyTypeClass> auxClasses,
             final Collection<? extends PlainAttr<?>> attrs,
             final Collection<? extends DerAttr<?>> derAttrs,
-            final Collection<? extends VirAttr<?>> virAttrs,
+            final Map<VirSchema, List<String>> virAttrs,
             final Collection<? extends ExternalResource> resources) {
 
         anyTO.setRealm(realmFullPath);
@@ -659,11 +635,11 @@ abstract class AbstractAnyDataBinder {
             anyTO.getDerAttrs().add(attrTO);
         }
 
-        for (VirAttr<?> virAttr : virAttrs) {
+        for (Map.Entry<VirSchema, List<String>> entry : virAttrs.entrySet()) {
             AttrTO attrTO = new AttrTO();
-            attrTO.setSchema(virAttr.getSchema().getKey());
-            attrTO.getValues().addAll(virAttr.getValues());
-            attrTO.setReadonly(virAttr.getSchema().isReadonly());
+            attrTO.setSchema(entry.getKey().getKey());
+            attrTO.getValues().addAll(entry.getValue());
+            attrTO.setReadonly(entry.getKey().isReadonly());
 
             anyTO.getVirAttrs().add(attrTO);
         }
@@ -673,21 +649,21 @@ abstract class AbstractAnyDataBinder {
         }
     }
 
-    protected RelationshipTO getRelationshipTO(final Relationship<? extends Any<?, ?, ?>, AnyObject> relationship) {
+    protected RelationshipTO getRelationshipTO(final Relationship<? extends Any<?, ?>, AnyObject> relationship) {
         return new RelationshipTO.Builder().
                 left(relationship.getLeftEnd().getType().getKey(), relationship.getLeftEnd().getKey()).
                 right(relationship.getRightEnd().getType().getKey(), relationship.getRightEnd().getKey()).
                 build();
     }
 
-    protected MembershipTO getMembershipTO(final Membership<? extends Any<?, ?, ?>> membership) {
+    protected MembershipTO getMembershipTO(final Membership<? extends Any<?, ?>> membership) {
         return new MembershipTO.Builder().
                 left(membership.getLeftEnd().getType().getKey(), membership.getLeftEnd().getKey()).
                 group(membership.getRightEnd().getKey(), membership.getRightEnd().getName()).
                 build();
     }
 
-    protected Map<String, String> getConnObjectKeys(final Any<?, ?, ?> any) {
+    protected Map<String, String> getConnObjectKeys(final Any<?, ?> any) {
         Map<String, String> connObjectKeys = new HashMap<>();
 
         Iterable<? extends ExternalResource> iterable = any instanceof User

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
index 91edd7e..2dca6e4 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -19,7 +19,9 @@
 package org.apache.syncope.core.provisioning.java.data;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
@@ -41,6 +43,7 @@ import org.apache.syncope.core.misc.spring.BeanUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.RelationshipType;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ARelationship;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
@@ -75,12 +78,12 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
 
         BeanUtils.copyProperties(anyObject, anyObjectTO, IGNORE_PROPERTIES);
 
-        if (details) {
-            virAttrHander.retrieveVirAttrValues(anyObject);
-        }
+        Map<VirSchema, List<String>> virAttrValues = details
+                ? virAttrHander.getValues(anyObject)
+                : Collections.<VirSchema, List<String>>emptyMap();
 
         fillTO(anyObjectTO, anyObject.getRealm().getFullPath(), anyObject.getAuxClasses(),
-                anyObject.getPlainAttrs(), anyObject.getDerAttrs(), anyObject.getVirAttrs(),
+                anyObject.getPlainAttrs(), anyObject.getDerAttrs(), virAttrValues,
                 anyObjectDAO.findAllResources(anyObject));
 
         if (details) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
index 155034c..620cdf8 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
@@ -18,6 +18,8 @@
  */
 package org.apache.syncope.core.provisioning.java.data;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
@@ -34,6 +36,7 @@ import org.apache.syncope.core.provisioning.api.data.GroupDataBinder;
 import org.apache.syncope.core.misc.search.SearchCondConverter;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.DynGroupMembership;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.user.UDynGroupMembership;
 import org.springframework.stereotype.Component;
@@ -203,12 +206,12 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
             groupTO.setGroupOwner(group.getGroupOwner().getKey());
         }
 
-        if (details) {
-            virAttrHander.retrieveVirAttrValues(group);
-        }
+        Map<VirSchema, List<String>> virAttrValues = details
+                ? virAttrHander.getValues(group)
+                : Collections.<VirSchema, List<String>>emptyMap();
 
         fillTO(groupTO, group.getRealm().getFullPath(), group.getAuxClasses(),
-                group.getPlainAttrs(), group.getDerAttrs(), group.getVirAttrs(), group.getResources());
+                group.getPlainAttrs(), group.getDerAttrs(), virAttrValues, group.getResources());
 
         if (group.getADynMembership() != null) {
             groupTO.setADynMembershipCond(group.getADynMembership().getFIQLCond());

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index e5dfadf..d04dfd3 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -21,9 +21,8 @@ package org.apache.syncope.core.provisioning.java.data;
 import org.apache.syncope.core.provisioning.api.data.ResourceDataBinder;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Set;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 import org.apache.syncope.common.lib.SyncopeClientException;
@@ -50,7 +49,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.syncope.core.misc.spring.BeanUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -76,6 +77,9 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
     private PolicyDAO policyDAO;
 
     @Autowired
+    private VirSchemaDAO virSchemaDAO;
+
+    @Autowired
     private EntityFactory entityFactory;
 
     @Override
@@ -112,7 +116,8 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
         for (ProvisionTO provisionTO : resourceTO.getProvisions()) {
             AnyType anyType = anyTypeDAO.find(provisionTO.getAnyType());
             if (anyType == null) {
-                LOG.debug("Invalid AnyType specified {}, ignoring...", provisionTO.getAnyType());
+                LOG.debug("Invalid {} specified {}, ignoring...",
+                        AnyType.class.getSimpleName(), provisionTO.getAnyType());
             } else {
                 Provision provision = resource.getProvision(anyType);
                 if (provision == null) {
@@ -124,7 +129,7 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
 
                 if (provisionTO.getObjectClass() == null) {
                     SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidProvision);
-                    sce.getElements().add("Null ObjectClass");
+                    sce.getElements().add("Null " + ObjectClass.class.getSimpleName());
                     throw sce;
                 }
                 provision.setObjectClass(new ObjectClass(provisionTO.getObjectClass()));
@@ -146,17 +151,36 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
                     }
                     populateMapping(provisionTO.getMapping(), mapping, entityFactory.newEntity(MappingItem.class));
                 }
+
+                if (provisionTO.getVirSchemas().isEmpty()) {
+                    for (VirSchema schema : virSchemaDAO.findByProvision(provision)) {
+                        virSchemaDAO.delete(schema.getKey());
+                    }
+                } else {
+                    for (String schemaName : provisionTO.getVirSchemas()) {
+                        VirSchema schema = virSchemaDAO.find(schemaName);
+                        if (schema == null) {
+                            LOG.debug("Invalid {} specified: {}, ignoring...",
+                                    VirSchema.class.getSimpleName(), schemaName);
+                        } else {
+                            schema.setProvision(provision);
+                        }
+                    }
+                }
             }
         }
 
-        // 2. remove all abouts not contained in the TO
-        CollectionUtils.filter(resource.getProvisions(), new Predicate<Provision>() {
+        // 2. remove all provisions not contained in the TO
+        for (Iterator<? extends Provision> itor = resource.getProvisions().iterator(); itor.hasNext();) {
+            Provision provision = itor.next();
+            if (resourceTO.getProvision(provision.getAnyType().getKey()) == null) {
+                for (VirSchema schema : virSchemaDAO.findByProvision(provision)) {
+                    virSchemaDAO.delete(schema.getKey());
+                }
 
-            @Override
-            public boolean evaluate(final Provision provision) {
-                return resourceTO.getProvision(provision.getAnyType().getKey()) != null;
+                itor.remove();
             }
-        });
+        }
 
         resource.setCreateTraceLevel(resourceTO.getCreateTraceLevel());
         resource.setUpdateTraceLevel(resourceTO.getUpdateTraceLevel());
@@ -310,6 +334,10 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
                 populateMappingTO(provision.getMapping(), mappingTO);
             }
 
+            for (VirSchema virSchema : virSchemaDAO.findByProvision(provision)) {
+                provisionTO.getVirSchemas().add(virSchema.getKey());
+            }
+
             resourceTO.getProvisions().add(provisionTO);
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java
index 0794f8c..006a998 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java
@@ -35,11 +35,13 @@ import org.apache.syncope.core.misc.spring.BeanUtils;
 import org.apache.syncope.core.misc.jexl.JexlUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -50,7 +52,7 @@ public class SchemaDataBinderImpl implements SchemaDataBinder {
 
     private static final Logger LOG = LoggerFactory.getLogger(SchemaDataBinder.class);
 
-    private static final String[] IGNORE_PROPERTIES = { "anyTypeClass" };
+    private static final String[] IGNORE_PROPERTIES = { "anyTypeClass", "provision" };
 
     @Autowired
     private AnyTypeClassDAO anyTypeClassDAO;
@@ -65,6 +67,9 @@ public class SchemaDataBinderImpl implements SchemaDataBinder {
     private VirSchemaDAO virSchemaDAO;
 
     @Autowired
+    private ExternalResourceDAO resourceDAO;
+
+    @Autowired
     private EntityFactory entityFactory;
 
     @Autowired
@@ -235,6 +240,14 @@ public class SchemaDataBinderImpl implements SchemaDataBinder {
             merged.setAnyTypeClass(null);
         }
 
+        Provision provision = resourceDAO.findProvision(schemaTO.getProvision());
+        if (provision == null) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSchemaDefinition);
+            sce.getElements().add("Provision " + schemaTO.getProvision() + " not found");
+            throw sce;
+        }
+        merged.setProvision(provision);
+
         return merged;
     }
 
@@ -253,6 +266,7 @@ public class SchemaDataBinderImpl implements SchemaDataBinder {
         VirSchemaTO schemaTO = new VirSchemaTO();
         BeanUtils.copyProperties(schema, schemaTO, IGNORE_PROPERTIES);
         schemaTO.setAnyTypeClass(schema.getAnyTypeClass() == null ? null : schema.getAnyTypeClass().getKey());
+        schemaTO.setProvision(schema.getProvision().getKey());
 
         return schemaTO;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index 3420d27..4bb7bdf 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -19,8 +19,10 @@
 package org.apache.syncope.core.provisioning.java.data;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import javax.annotation.Resource;
@@ -57,6 +59,7 @@ import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
@@ -431,12 +434,12 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             userTO.setSecurityQuestion(user.getSecurityQuestion().getKey());
         }
 
-        if (details) {
-            virAttrHander.retrieveVirAttrValues(user);
-        }
+        Map<VirSchema, List<String>> virAttrValues = details
+                ? virAttrHander.getValues(user)
+                : Collections.<VirSchema, List<String>>emptyMap();
 
         fillTO(userTO, user.getRealm().getFullPath(), user.getAuxClasses(),
-                user.getPlainAttrs(), user.getDerAttrs(), user.getVirAttrs(), userDAO.findAllResources(user));
+                user.getPlainAttrs(), user.getDerAttrs(), virAttrValues, userDAO.findAllResources(user));
 
         if (details) {
             // roles

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
index dbfeca5..7c6d34c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
@@ -21,7 +21,7 @@ package org.apache.syncope.core.provisioning.java.job;
 import java.util.Date;
 import java.util.concurrent.atomic.AtomicReference;
 import org.apache.commons.lang3.ClassUtils;
-import org.apache.syncope.core.misc.DataFormat;
+import org.apache.syncope.core.misc.FormatUtils;
 import org.apache.syncope.core.misc.security.AuthContextUtils;
 import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 import org.apache.syncope.core.provisioning.api.job.JobInstanceLoader;
@@ -114,7 +114,7 @@ public class TaskJob implements InterruptableJob {
         if (thread == null) {
             LOG.warn("Unable to retrieve the thread of the current job execution");
         } else {
-            LOG.info("Interrupting job from thread {} at {} ", thread.getId(), DataFormat.format(new Date()));
+            LOG.info("Interrupting job from thread {} at {} ", thread.getId(), FormatUtils.format(new Date()));
 
             if (interruptMaxRetries < 1) {
                 interruptMaxRetries = 1;

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
index 412b978..fd4af1b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
@@ -50,16 +50,17 @@ import org.apache.syncope.core.persistence.api.entity.task.NotificationTask;
 import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
 import org.apache.syncope.core.persistence.api.entity.user.UDerAttr;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
-import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.data.GroupDataBinder;
 import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 import org.apache.syncope.core.misc.search.SearchCondConverter;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyAbout;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.VelocityEngine;
@@ -76,9 +77,6 @@ import org.springframework.transaction.annotation.Transactional;
 @Transactional(rollbackFor = { Throwable.class })
 public class NotificationManagerImpl implements NotificationManager {
 
-    /**
-     * Logger.
-     */
     private static final Logger LOG = LoggerFactory.getLogger(NotificationManager.class);
 
     public static final String MAIL_TEMPLATES = "mailTemplates/";
@@ -87,6 +85,9 @@ public class NotificationManagerImpl implements NotificationManager {
 
     public static final String MAIL_TEMPLATE_TEXT_SUFFIX = ".txt.vm";
 
+    @Autowired
+    private VirSchemaDAO virSchemaDAO;
+
     /**
      * Notification DAO.
      */
@@ -169,11 +170,11 @@ public class NotificationManagerImpl implements NotificationManager {
      */
     private NotificationTask getNotificationTask(
             final Notification notification,
-            final Any<?, ?, ?> any,
+            final Any<?, ?> any,
             final Map<String, Object> model) {
 
         if (any != null) {
-            virAttrHander.retrieveVirAttrValues(any);
+            virAttrHander.getValues(any);
         }
 
         List<User> recipients = new ArrayList<>();
@@ -191,7 +192,7 @@ public class NotificationManagerImpl implements NotificationManager {
         Set<String> recipientEmails = new HashSet<>();
         List<UserTO> recipientTOs = new ArrayList<>(recipients.size());
         for (User recipient : recipients) {
-            virAttrHander.retrieveVirAttrValues(recipient);
+            virAttrHander.getValues(recipient);
 
             String email = getRecipientEmail(notification.getRecipientAttrType(),
                     notification.getRecipientAttrName(), recipient);
@@ -267,7 +268,7 @@ public class NotificationManagerImpl implements NotificationManager {
             final Object output,
             final Object... input) {
 
-        Any<?, ?, ?> any = null;
+        Any<?, ?> any = null;
 
         if (before instanceof UserTO) {
             any = userDAO.find(((UserTO) before).getKey());
@@ -357,9 +358,12 @@ public class NotificationManagerImpl implements NotificationManager {
                 break;
 
             case UserVirtualSchema:
-                UVirAttr virAttr = user.getVirAttr(recipientAttrName);
-                if (virAttr != null) {
-                    email = virAttr.getValues().isEmpty() ? null : virAttr.getValues().get(0);
+                VirSchema schema = virSchemaDAO.find(recipientAttrName);
+                if (schema == null) {
+                    LOG.warn("Ignoring non existing {} {}", VirSchema.class.getSimpleName(), recipientAttrName);
+                } else {
+                    List<String> virAttrValues = virAttrHander.getValues(user, schema);
+                    email = virAttrValues.isEmpty() ? null : virAttrValues.get(0);
                 }
                 break;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
index 69a2e9d..316f91a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
@@ -27,6 +27,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import org.apache.commons.collections4.IteratorUtils;
 import org.apache.syncope.common.lib.types.AuditElements;
 import org.apache.syncope.common.lib.types.AuditElements.Result;
 import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
@@ -49,12 +50,17 @@ import org.apache.syncope.core.misc.ConnObjectUtils;
 import org.apache.syncope.core.misc.ExceptionUtils2;
 import org.apache.syncope.core.misc.MappingUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
+import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
 import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
 import org.identityconnectors.framework.common.exceptions.ConnectorException;
 import org.identityconnectors.framework.common.objects.Attribute;
@@ -110,6 +116,9 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
     @Autowired
     protected TaskDAO taskDAO;
 
+    @Autowired
+    protected VirSchemaDAO virSchemaDAO;
+
     /**
      * Notification Manager.
      */
@@ -125,6 +134,9 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
     @Autowired
     protected EntityFactory entityFactory;
 
+    @Autowired
+    protected VirAttrCache virAttrCache;
+
     @Override
     public TaskExec execute(final PropagationTask task) {
         return execute(task, null);
@@ -149,12 +161,15 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
     }
 
     /**
-     * Transform a
-     * <code>Collection</code> of {@link Attribute} instances into a {@link Map}. The key to each element in the map is
-     * the <i>name</i> of an
-     * <code>Attribute</code>. The value of each element in the map is the
-     * <code>Attribute</code> instance with that name. <br/> Different from the original because: <ul> <li>map keys are
-     * transformed toUpperCase()</li> <li>returned map is mutable</li> </ul>
+     * Transform a {@link Collection} of {@link Attribute} instances into a {@link Map}.
+     * The key to each element in the map is the {@code name} of an {@link Attribute}.
+     * The value of each element in the map is the {@link Attribute} instance with that name.
+     * <br/>
+     * Different from the original because:
+     * <ul>
+     * <li>map keys are transformed toUpperCase()</li>
+     * <li>returned map is mutable</li>
+     * </ul>
      *
      * @param attributes set of attribute to transform to a map.
      * @return a map of string and attribute.
@@ -173,7 +188,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
             final PropagationTask task,
             final ConnectorObject beforeObj,
             final Connector connector,
-            final Set<String> propagationAttempted) {
+            final Boolean[] propagationAttempted) {
 
         // set of attributes to be propagated
         Set<Attribute> attributes = new HashSet<>(task.getAttributes());
@@ -201,14 +216,10 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
 
         if (beforeObj == null) {
             LOG.debug("Create {} on {}", attributes, task.getResource().getKey());
-            connector.create(
-                    new ObjectClass(task.getObjectClassName()),
-                    attributes,
-                    null,
-                    propagationAttempted);
+            connector.create(new ObjectClass(task.getObjectClassName()), attributes, null, propagationAttempted);
         } else {
             // 1. check if rename is really required
-            final Name newName = (Name) AttributeUtil.find(Name.NAME, attributes);
+            Name newName = (Name) AttributeUtil.find(Name.NAME, attributes);
 
             LOG.debug("Rename required with value {}", newName);
 
@@ -254,8 +265,8 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
         }
     }
 
-    protected Any<?, ?, ?> getAny(final PropagationTask task) {
-        Any<?, ?, ?> any = null;
+    protected Any<?, ?> getAny(final PropagationTask task) {
+        Any<?, ?> any = null;
 
         if (task.getAnyKey() != null) {
             switch (task.getAnyTypeKind()) {
@@ -289,8 +300,11 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
         return any;
     }
 
-    protected void delete(final PropagationTask task, final ConnectorObject beforeObj,
-            final Connector connector, final Set<String> propagationAttempted) {
+    protected void delete(
+            final PropagationTask task,
+            final ConnectorObject beforeObj,
+            final Connector connector,
+            final Boolean[] propagationAttempted) {
 
         if (beforeObj == null) {
             LOG.debug("{} not found on external resource: ignoring delete", task.getConnObjectKey());
@@ -310,7 +324,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
              * update, this user / group used to have the current resource assigned by more than one mean (for example,
              * two different memberships with the same resource).
              */
-            Any<?, ?, ?> any = getAny(task);
+            Any<?, ?> any = getAny(task);
             Collection<String> resources = any instanceof User
                     ? userDAO.findAllResourceNames((User) any)
                     : any instanceof AnyObject
@@ -321,11 +335,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
             if (!resources.contains(task.getResource().getKey())) {
                 LOG.debug("Delete {} on {}", beforeObj.getUid(), task.getResource().getKey());
 
-                connector.delete(
-                        beforeObj.getObjectClass(),
-                        beforeObj.getUid(),
-                        null,
-                        propagationAttempted);
+                connector.delete(beforeObj.getObjectClass(), beforeObj.getUid(), null, propagationAttempted);
             } else {
                 createOrUpdate(task, beforeObj, connector, propagationAttempted);
             }
@@ -345,7 +355,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
         String failureReason = null;
 
         // Flag to state whether any propagation has been attempted
-        Set<String> propagationAttempted = new HashSet<>();
+        Boolean[] propagationAttempted = new Boolean[] { false };
 
         ConnectorObject beforeObj = null;
         ConnectorObject afterObj = null;
@@ -411,7 +421,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
                 LOG.error("While executing KO action on {}", execution, wft);
             }
 
-            propagationAttempted.add(task.getOperation().name().toLowerCase());
+            propagationAttempted[0] = true;
 
             for (PropagationActions action : actions) {
                 action.onError(task, execution, e);
@@ -434,7 +444,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
             execution.setEndDate(new Date());
 
             if (hasToBeregistered(task, execution)) {
-                if (propagationAttempted.isEmpty()) {
+                if (!propagationAttempted[0]) {
                     LOG.debug("No propagation attempted for {}", execution);
                 } else {
                     execution.setTask(task);
@@ -535,20 +545,41 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
      * @param latest 'FALSE' to retrieve object using old connObjectKey if not null.
      * @return remote connector object.
      */
-    protected ConnectorObject getRemoteObject(final PropagationTask task, final Connector connector,
-            final Provision provision, final boolean latest) {
+    protected ConnectorObject getRemoteObject(
+            final PropagationTask task,
+            final Connector connector,
+            final Provision provision,
+            final boolean latest) {
 
         String connObjectKey = latest || task.getOldConnObjectKey() == null
                 ? task.getConnObjectKey()
                 : task.getOldConnObjectKey();
 
+        List<MappingItem> linkingMappingItems = new ArrayList<>();
+        for (VirSchema schema : virSchemaDAO.findByProvision(provision)) {
+            linkingMappingItems.add(schema.asLinkingMappingItem());
+        }
+
         ConnectorObject obj = null;
         try {
             obj = connector.getObject(
                     task.getOperation(),
                     new ObjectClass(task.getObjectClassName()),
                     new Uid(connObjectKey),
-                    connector.getOperationOptions(MappingUtils.getPropagationMappingItems(provision)));
+                    connector.getOperationOptions(IteratorUtils.chainedIterator(
+                                    MappingUtils.getPropagationMappingItems(provision).iterator(),
+                                    linkingMappingItems.iterator())));
+
+            for (MappingItem item : linkingMappingItems) {
+                Attribute attr = obj.getAttributeByName(item.getExtAttrName());
+                if (attr == null) {
+                    virAttrCache.expire(task.getAnyType(), task.getAnyKey(), item.getIntAttrName());
+                } else {
+                    VirAttrCacheValue cacheValue = new VirAttrCacheValue();
+                    cacheValue.setValues(attr.getValue());
+                    virAttrCache.put(task.getAnyType(), task.getAnyKey(), item.getIntAttrName(), cacheValue);
+                }
+            }
         } catch (TimeoutException toe) {
             LOG.debug("Request timeout", toe);
             throw toe;


[12/54] [abbrv] syncope git commit: Upgrading release plugin

Posted by fm...@apache.org.
Upgrading release plugin


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

Branch: refs/heads/SYNCOPE-156
Commit: 03c9bc2fe57b825a1cdfa4e8eb0fa0ce66ec40b0
Parents: 2524280
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Mon Oct 19 09:56:54 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Mon Oct 19 09:56:54 2015 +0200

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/03c9bc2f/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 67ec907..e4b3787 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1482,7 +1482,7 @@ under the License.
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-release-plugin</artifactId>
-        <version>2.5.2</version>
+        <version>2.5.3</version>
         <configuration>
           <mavenExecutorId>forked-path</mavenExecutorId>
           <autoVersionSubmodules>true</autoVersionSubmodules>


[46/54] [abbrv] syncope git commit: Removing @Column(nullable = false) in favor of @NotNull - better error messages

Posted by fm...@apache.org.
Removing @Column(nullable = false) in favor of @NotNull - better error messages


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

Branch: refs/heads/SYNCOPE-156
Commit: e20dd0ae315244db0f74b29ffe6096760a7536b6
Parents: 9cd9230
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 22 12:22:06 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 22 12:22:06 2015 +0200

----------------------------------------------------------------------
 .../persistence/jpa/entity/AbstractExec.java    |  4 ++--
 .../persistence/jpa/entity/JPAConnInstance.java |  9 +++++----
 .../persistence/jpa/entity/JPADerSchema.java    |  4 ++--
 .../persistence/jpa/entity/JPANotification.java |  4 ++--
 .../persistence/jpa/entity/JPAPlainSchema.java  |  5 +++--
 .../persistence/jpa/entity/JPAVirSchema.java    |  6 +++---
 .../entity/resource/JPAExternalResource.java    | 16 ++++++++--------
 .../jpa/entity/resource/JPAMapping.java         |  4 ++--
 .../jpa/entity/resource/JPAMappingItem.java     | 11 ++++++-----
 .../persistence/jpa/inner/AnyObjectTest.java    |  5 +++++
 .../persistence/jpa/inner/VirSchemaTest.java    | 12 ++++++++++++
 .../java/data/SchemaDataBinderImpl.java         | 20 +++++++++-----------
 .../fit/core/reference/VirSchemaITCase.java     |  9 ++++++++-
 13 files changed, 67 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractExec.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractExec.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractExec.java
index 5c009d4..a9b5c13 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractExec.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractExec.java
@@ -20,11 +20,11 @@ package org.apache.syncope.core.persistence.jpa.entity;
 
 import java.util.Date;
 
-import javax.persistence.Column;
 import javax.persistence.Lob;
 import javax.persistence.MappedSuperclass;
 import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
+import javax.validation.constraints.NotNull;
 import org.apache.syncope.core.persistence.api.entity.Exec;
 
 @MappedSuperclass
@@ -32,7 +32,7 @@ public abstract class AbstractExec extends AbstractEntity<Long> implements Exec
 
     private static final long serialVersionUID = -812344822970166317L;
 
-    @Column(nullable = false)
+    @NotNull
     protected String status;
 
     /**

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
index 3929496..054dd69 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
@@ -36,6 +36,7 @@ import javax.persistence.JoinColumn;
 import javax.persistence.Lob;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
@@ -63,7 +64,7 @@ public class JPAConnInstance extends AbstractEntity<Long> implements ConnInstanc
     /**
      * URI identifying the local / remote ConnId location where the related connector bundle is found.
      */
-    @Column(nullable = false)
+    @NotNull
     private String location;
 
     /**
@@ -71,7 +72,7 @@ public class JPAConnInstance extends AbstractEntity<Long> implements ConnInstanc
      * Within a given location, the triple
      * (ConnectorBundle-Name, ConnectorBundle-Version, ConnectorBundle-Version) must be unique.
      */
-    @Column(nullable = false)
+    @NotNull
     private String connectorName;
 
     /**
@@ -79,7 +80,7 @@ public class JPAConnInstance extends AbstractEntity<Long> implements ConnInstanc
      * Within a given location, the triple
      * (ConnectorBundle-Name, ConnectorBundle-Version, ConnectorBundle-Version) must be unique.
      */
-    @Column(nullable = false)
+    @NotNull
     private String bundleName;
 
     /**
@@ -87,7 +88,7 @@ public class JPAConnInstance extends AbstractEntity<Long> implements ConnInstanc
      * Within a given location, the triple
      * (ConnectorBundle-Name, ConnectorBundle-Version, ConnectorBundle-Version) must be unique.
      */
-    @Column(nullable = false)
+    @NotNull
     private String version;
 
     /**

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADerSchema.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADerSchema.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADerSchema.java
index 944afc4..45eea22 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADerSchema.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPADerSchema.java
@@ -19,12 +19,12 @@
 package org.apache.syncope.core.persistence.jpa.entity;
 
 import javax.persistence.Cacheable;
-import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.Id;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
@@ -46,7 +46,7 @@ public class JPADerSchema extends AbstractEntity<String> implements DerSchema {
     @OneToOne(fetch = FetchType.EAGER)
     private JPAAnyTypeClass anyTypeClass;
 
-    @Column(nullable = false)
+    @NotNull
     private String expression;
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANotification.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANotification.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANotification.java
index 7e3d211..1c42cf0 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANotification.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPANotification.java
@@ -84,7 +84,7 @@ public class JPANotification extends AbstractEntity<Long> implements Notificatio
     @NotNull
     private String recipientAttrName;
 
-    @Column(nullable = false)
+    @NotNull
     @Basic
     @Min(0)
     @Max(1)
@@ -103,7 +103,7 @@ public class JPANotification extends AbstractEntity<Long> implements Notificatio
     @Enumerated(EnumType.STRING)
     private TraceLevel traceLevel;
 
-    @Column(nullable = false)
+    @NotNull
     @Basic
     @Min(0)
     @Max(1)

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAPlainSchema.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAPlainSchema.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAPlainSchema.java
index 68eeacf..4ba6fa3 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAPlainSchema.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAPlainSchema.java
@@ -32,6 +32,7 @@ import javax.persistence.Table;
 import javax.persistence.Transient;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
@@ -58,11 +59,11 @@ public class JPAPlainSchema extends AbstractEntity<String> implements PlainSchem
     @OneToOne(fetch = FetchType.EAGER)
     private JPAAnyTypeClass anyTypeClass;
 
-    @Column(nullable = false)
+    @NotNull
     @Enumerated(EnumType.STRING)
     private AttrSchemaType type;
 
-    @Column(nullable = false)
+    @NotNull
     private String mandatoryCondition;
 
     @Basic

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
index b984bb3..419e93a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
@@ -22,7 +22,6 @@ import java.util.Collections;
 import java.util.List;
 import javax.persistence.Basic;
 import javax.persistence.Cacheable;
-import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.Id;
@@ -31,6 +30,7 @@ import javax.persistence.OneToOne;
 import javax.persistence.Table;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
@@ -63,11 +63,11 @@ public class JPAVirSchema extends AbstractEntity<String> implements VirSchema {
     @Max(1)
     private Integer readonly;
 
-    @Column(nullable = false)
+    @NotNull
     @ManyToOne
     private JPAProvision provision;
 
-    @Column(nullable = false)
+    @NotNull
     private String extAttrName;
 
     public JPAVirSchema() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
index e9e59fd..de3931e 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
@@ -82,7 +82,7 @@ public class JPAExternalResource extends AbstractAnnotatedEntity<String> impleme
     /**
      * Should this resource enforce the mandatory constraints?
      */
-    @Column(nullable = false)
+    @NotNull
     @Basic
     @Min(0)
     @Max(1)
@@ -101,7 +101,7 @@ public class JPAExternalResource extends AbstractAnnotatedEntity<String> impleme
     /**
      * Is this resource primary, for propagations?
      */
-    @Column(nullable = false)
+    @NotNull
     @Basic
     @Min(0)
     @Max(1)
@@ -110,32 +110,32 @@ public class JPAExternalResource extends AbstractAnnotatedEntity<String> impleme
     /**
      * Priority index for propagation ordering.
      */
-    @Column(nullable = false)
+    @NotNull
     private Integer propagationPriority;
 
     /**
      * Generate random password for propagation, if not provided?
      */
-    @Column(nullable = false)
+    @NotNull
     @Basic
     @Min(0)
     @Max(1)
     private Integer randomPwdIfNotProvided;
 
     @Enumerated(EnumType.STRING)
-    @Column(nullable = false)
+    @NotNull
     private TraceLevel createTraceLevel;
 
     @Enumerated(EnumType.STRING)
-    @Column(nullable = false)
+    @NotNull
     private TraceLevel updateTraceLevel;
 
     @Enumerated(EnumType.STRING)
-    @Column(nullable = false)
+    @NotNull
     private TraceLevel deleteTraceLevel;
 
     @Enumerated(EnumType.STRING)
-    @Column(nullable = false)
+    @NotNull
     private TraceLevel syncTraceLevel;
 
     @ManyToOne(fetch = FetchType.EAGER)

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMapping.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMapping.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMapping.java
index 2d7af3c..872fee7 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMapping.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMapping.java
@@ -22,13 +22,13 @@ import java.util.ArrayList;
 import java.util.List;
 import javax.persistence.Cacheable;
 import javax.persistence.CascadeType;
-import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.Id;
 import javax.persistence.OneToMany;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.common.lib.types.IntMappingType;
@@ -49,7 +49,7 @@ public class JPAMapping extends AbstractEntity<Long> implements Mapping {
     @Id
     private Long id;
 
-    @Column(nullable = false)
+    @NotNull
     @OneToOne
     private JPAProvision provision;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
index 8dba286..c3ee73b 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
@@ -35,6 +35,7 @@ import javax.persistence.ManyToOne;
 import javax.persistence.Table;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
 import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
@@ -59,7 +60,7 @@ public class JPAMappingItem extends AbstractEntity<Long> implements MappingItem
     @Column(nullable = true)
     private String intAttrName;
 
-    @Column(nullable = false)
+    @NotNull
     @Enumerated(EnumType.STRING)
     private IntMappingType intMappingType;
 
@@ -72,13 +73,13 @@ public class JPAMappingItem extends AbstractEntity<Long> implements MappingItem
     /**
      * Specify if the mapped target resource's field is nullable.
      */
-    @Column(nullable = false)
+    @NotNull
     private String mandatoryCondition;
 
     /**
      * Specify if the mapped target resource's field is the key.
      */
-    @Column(nullable = false)
+    @NotNull
     @Basic
     @Min(0)
     @Max(1)
@@ -87,13 +88,13 @@ public class JPAMappingItem extends AbstractEntity<Long> implements MappingItem
     /**
      * Specify if the mapped target resource's field is the password.
      */
-    @Column(nullable = false)
+    @NotNull
     @Basic
     @Min(0)
     @Max(1)
     private Integer password;
 
-    @Column(nullable = false)
+    @NotNull
     @Enumerated(EnumType.STRING)
     private MappingPurpose purpose;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
index cd6b535..943a94f 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
@@ -26,6 +26,7 @@ import static org.junit.Assert.assertTrue;
 import java.util.List;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
+import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
@@ -37,6 +38,9 @@ import org.springframework.transaction.annotation.Transactional;
 public class AnyObjectTest extends AbstractTest {
 
     @Autowired
+    private AnyTypeDAO anyTypeDAO;
+
+    @Autowired
     private AnyObjectDAO anyObjectDAO;
 
     @Autowired
@@ -68,6 +72,7 @@ public class AnyObjectTest extends AbstractTest {
     @Test
     public void save() {
         AnyObject anyObject = entityFactory.newEntity(AnyObject.class);
+        anyObject.setType(anyTypeDAO.find("PRINTER"));
         anyObject.setRealm(realmDAO.find(SyncopeConstants.ROOT_REALM));
 
         anyObject = anyObjectDAO.save(anyObject);

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirSchemaTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirSchemaTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirSchemaTest.java
index 66bd6cb..19193dd 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirSchemaTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirSchemaTest.java
@@ -27,9 +27,13 @@ import static org.junit.Assert.fail;
 import java.util.List;
 import org.apache.syncope.common.lib.types.EntityViolationType;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -40,6 +44,9 @@ public class VirSchemaTest extends AbstractTest {
     @Autowired
     private VirSchemaDAO virSchemaDAO;
 
+    @Autowired
+    private ExternalResourceDAO resourceDAO;
+
     @Test
     public void findAll() {
         List<VirSchema> list = virSchemaDAO.findAll();
@@ -54,8 +61,13 @@ public class VirSchemaTest extends AbstractTest {
 
     @Test
     public void save() {
+        ExternalResource csv = resourceDAO.find("resource-csv");
+        Provision provision = csv.getProvision(ObjectClass.ACCOUNT);
+        assertNotNull(provision);
+
         VirSchema virSchema = entityFactory.newEntity(VirSchema.class);
         virSchema.setKey("virtual");
+        virSchema.setProvision(provision);
         virSchema.setReadonly(true);
         virSchema.setExtAttrName("EXT_ATTR");
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java
index 006a998..6e9837f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java
@@ -221,23 +221,21 @@ public class SchemaDataBinderImpl implements SchemaDataBinder {
     private VirSchema fill(final VirSchema schema, final VirSchemaTO schemaTO) {
         BeanUtils.copyProperties(schemaTO, schema, IGNORE_PROPERTIES);
 
-        VirSchema merged = virSchemaDAO.save(schema);
-
         if (schemaTO.getAnyTypeClass() != null
-                && (merged.getAnyTypeClass() == null
-                || !schemaTO.getAnyTypeClass().equals(merged.getAnyTypeClass().getKey()))) {
+                && (schema.getAnyTypeClass() == null
+                || !schemaTO.getAnyTypeClass().equals(schema.getAnyTypeClass().getKey()))) {
 
             AnyTypeClass anyTypeClass = anyTypeClassDAO.find(schemaTO.getAnyTypeClass());
             if (anyTypeClass == null) {
                 LOG.debug("Invalid " + AnyTypeClass.class.getSimpleName()
                         + "{}, ignoring...", schemaTO.getAnyTypeClass());
             } else {
-                anyTypeClass.add(merged);
-                merged.setAnyTypeClass(anyTypeClass);
+                anyTypeClass.add(schema);
+                schema.setAnyTypeClass(anyTypeClass);
             }
-        } else if (schemaTO.getAnyTypeClass() == null && merged.getAnyTypeClass() != null) {
-            merged.getAnyTypeClass().remove(merged);
-            merged.setAnyTypeClass(null);
+        } else if (schemaTO.getAnyTypeClass() == null && schema.getAnyTypeClass() != null) {
+            schema.getAnyTypeClass().remove(schema);
+            schema.setAnyTypeClass(null);
         }
 
         Provision provision = resourceDAO.findProvision(schemaTO.getProvision());
@@ -246,9 +244,9 @@ public class SchemaDataBinderImpl implements SchemaDataBinder {
             sce.getElements().add("Provision " + schemaTO.getProvision() + " not found");
             throw sce;
         }
-        merged.setProvision(provision);
+        schema.setProvision(provision);
 
-        return merged;
+        return virSchemaDAO.save(schema);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/e20dd0ae/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirSchemaITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirSchemaITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirSchemaITCase.java
index caae156..c4e4ea0 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirSchemaITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/VirSchemaITCase.java
@@ -112,8 +112,15 @@ public class VirSchemaITCase extends AbstractITCase {
 
     @Test
     public void issueSYNCOPE418() {
+        ResourceTO ws1 = resourceService.read(RESOURCE_NAME_WS1);
+        assertNotNull(ws1);
+        assertEquals(1, ws1.getProvisions().size());
+        assertTrue(ws1.getProvisions().get(0).getVirSchemas().isEmpty());
+
         VirSchemaTO schema = new VirSchemaTO();
         schema.setKey("http://schemas.examples.org/security/authorization/organizationUnit");
+        schema.setExtAttrName("name");
+        schema.setProvision(ws1.getProvisions().get(0).getKey());
 
         try {
             createSchema(SchemaType.VIRTUAL, schema);
@@ -121,7 +128,7 @@ public class VirSchemaITCase extends AbstractITCase {
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.InvalidVirSchema, e.getType());
 
-            assertTrue(e.getElements().iterator().next().toString().contains(EntityViolationType.InvalidName.name()));
+            assertTrue(e.getElements().iterator().next().contains(EntityViolationType.InvalidName.name()));
         }
     }
 }


[02/54] [abbrv] syncope git commit: [SYNCOPE-710] Merge from 1_2_X

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
----------------------------------------------------------------------
diff --cc fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
index 283f532,0000000..7de863e
mode 100644,000000..100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
@@@ -1,2558 -1,0 +1,2590 @@@
 +/*
 + * 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 static org.junit.Assert.assertEquals;
 +import static org.junit.Assert.assertFalse;
 +import static org.junit.Assert.assertNotEquals;
 +import static org.junit.Assert.assertNotNull;
 +import static org.junit.Assert.assertNull;
 +import static org.junit.Assert.assertTrue;
 +import static org.junit.Assert.fail;
 +
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.security.AccessControlException;
 +import java.text.SimpleDateFormat;
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.Date;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +import javax.naming.NamingException;
 +import javax.ws.rs.core.EntityTag;
 +import javax.ws.rs.core.MediaType;
 +import javax.ws.rs.core.Response;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.cxf.common.util.Base64Utility;
 +import org.apache.cxf.helpers.IOUtils;
 +import org.apache.syncope.client.lib.SyncopeClient;
 +import org.apache.syncope.common.lib.AnyOperations;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.SyncopeConstants;
 +import org.apache.syncope.common.lib.patch.AssociationPatch;
 +import org.apache.syncope.common.lib.patch.AttrPatch;
 +import org.apache.syncope.common.lib.patch.DeassociationPatch;
 +import org.apache.syncope.common.lib.patch.MembershipPatch;
 +import org.apache.syncope.common.lib.patch.PasswordPatch;
 +import org.apache.syncope.common.lib.patch.StatusPatch;
 +import org.apache.syncope.common.lib.patch.StringPatchItem;
 +import org.apache.syncope.common.lib.patch.StringReplacePatchItem;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.common.lib.policy.AccountPolicyTO;
 +import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
 +import org.apache.syncope.common.lib.policy.PasswordPolicyTO;
 +import org.apache.syncope.common.lib.to.AttrTO;
 +import org.apache.syncope.common.lib.to.BulkAction;
 +import org.apache.syncope.common.lib.to.BulkActionResult;
 +import org.apache.syncope.common.lib.to.BulkActionResult.Status;
 +import org.apache.syncope.common.lib.to.ConnObjectTO;
 +import org.apache.syncope.common.lib.to.MappingItemTO;
 +import org.apache.syncope.common.lib.to.MappingTO;
 +import org.apache.syncope.common.lib.to.MembershipTO;
 +import org.apache.syncope.common.lib.to.PagedResult;
 +import org.apache.syncope.common.lib.to.PropagationStatus;
 +import org.apache.syncope.common.lib.to.PropagationTaskTO;
 +import org.apache.syncope.common.lib.to.ResourceTO;
 +import org.apache.syncope.common.lib.to.GroupTO;
 +import org.apache.syncope.common.lib.to.RealmTO;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.CipherAlgorithm;
 +import org.apache.syncope.common.lib.types.ClientExceptionType;
 +import org.apache.syncope.common.lib.types.MappingPurpose;
 +import org.apache.syncope.common.lib.types.PatchOperation;
 +import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
 +import org.apache.syncope.common.lib.types.ResourceAssociationAction;
 +import org.apache.syncope.common.lib.types.ResourceDeassociationAction;
 +import org.apache.syncope.common.lib.types.StatusPatchType;
 +import org.apache.syncope.common.lib.types.TaskType;
 +import org.apache.syncope.common.rest.api.Preference;
 +import org.apache.syncope.common.rest.api.RESTHeaders;
 +import org.apache.syncope.common.rest.api.service.ResourceService;
 +import org.apache.syncope.common.rest.api.service.UserSelfService;
 +import org.apache.syncope.common.rest.api.service.UserService;
 +import org.apache.syncope.core.misc.security.Encryptor;
 +import org.apache.syncope.core.provisioning.java.propagation.DBPasswordPropagationActions;
 +import org.apache.syncope.core.provisioning.java.propagation.LDAPPasswordPropagationActions;
 +import org.identityconnectors.framework.common.objects.Name;
 +import org.identityconnectors.framework.common.objects.OperationalAttributes;
 +import org.junit.Assume;
 +import org.junit.FixMethodOrder;
 +import org.junit.Test;
 +import org.junit.runners.MethodSorters;
 +import org.springframework.dao.EmptyResultDataAccessException;
 +import org.springframework.jdbc.core.JdbcTemplate;
 +
 +@FixMethodOrder(MethodSorters.JVM)
 +public class UserITCase extends AbstractITCase {
 +
 +    private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
 +
 +        @Override
 +        protected SimpleDateFormat initialValue() {
 +            SimpleDateFormat sdf = new SimpleDateFormat();
 +            sdf.applyPattern("yyyy-MM-dd");
 +            return sdf;
 +        }
 +    };
 +
 +    private boolean getBooleanAttribute(final ConnObjectTO connObjectTO, final String attrName) {
 +        return Boolean.parseBoolean(connObjectTO.getPlainAttrMap().get(attrName).getValues().get(0));
 +    }
 +
 +    public static UserTO getUniqueSampleTO(final String email) {
 +        return getSampleTO(getUUIDString() + email);
 +    }
 +
 +    public static UserTO getSampleTO(final String email) {
 +        UserTO userTO = new UserTO();
 +        userTO.setRealm(SyncopeConstants.ROOT_REALM);
 +        userTO.setPassword("password123");
 +        userTO.setUsername(email);
 +
 +        userTO.getPlainAttrs().add(attrTO("fullname", email));
 +        userTO.getPlainAttrs().add(attrTO("firstname", email));
 +        userTO.getPlainAttrs().add(attrTO("surname", "surname"));
 +        userTO.getPlainAttrs().add(attrTO("type", "a type"));
 +        userTO.getPlainAttrs().add(attrTO("userId", email));
 +        userTO.getPlainAttrs().add(attrTO("email", email));
 +        userTO.getPlainAttrs().add(attrTO("loginDate", DATE_FORMAT.get().format(new Date())));
 +        userTO.getDerAttrs().add(attrTO("cn", null));
 +        userTO.getVirAttrs().add(attrTO("virtualdata", "virtualvalue"));
 +        return userTO;
 +    }
 +
 +    @Test
 +    public void createUserWithNoPropagation() {
 +        // get task list
 +        PagedResult<PropagationTaskTO> tasks = taskService.list(
 +                TaskType.PROPAGATION,
 +                SyncopeClient.getTaskQueryBuilder().page(1).size(1).build());
 +        assertNotNull(tasks);
 +        assertFalse(tasks.getResult().isEmpty());
 +
 +        long maxKey = tasks.getResult().iterator().next().getKey();
 +
 +        // create a new user
 +        UserTO userTO = getUniqueSampleTO("xxx@xxx.xxx");
 +
 +        userTO.setPassword("password123");
 +        userTO.getResources().add(RESOURCE_NAME_NOPROPAGATION);
 +
 +        createUser(userTO);
 +
 +        // get the new task list
 +        tasks = taskService.list(
 +                TaskType.PROPAGATION,
 +                SyncopeClient.getTaskQueryBuilder().page(1).size(1).build());
 +        assertNotNull(tasks);
 +        assertFalse(tasks.getResult().isEmpty());
 +
 +        long newMaxId = tasks.getResult().iterator().next().getKey();
 +
 +        assertTrue(newMaxId > maxKey);
 +
 +        // get last task
 +        PropagationTaskTO taskTO = taskService.read(newMaxId);
 +
 +        assertNotNull(taskTO);
 +        assertTrue(taskTO.getExecutions().isEmpty());
 +    }
 +
 +    @Test
 +    public void issue186() {
 +        // 1. create an user with strict mandatory attributes only
 +        UserTO userTO = new UserTO();
 +        userTO.setRealm(SyncopeConstants.ROOT_REALM);
 +        String userId = getUUIDString() + "issue186@syncope.apache.org";
 +        userTO.setUsername(userId);
 +        userTO.setPassword("password123");
 +
 +        userTO.getPlainAttrs().add(attrTO("userId", userId));
 +        userTO.getPlainAttrs().add(attrTO("fullname", userId));
 +        userTO.getPlainAttrs().add(attrTO("surname", userId));
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +        assertTrue(userTO.getResources().isEmpty());
 +
 +        // 2. update assigning a resource forcing mandatory constraints: must fail with RequiredValuesMissing
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().value("newPassword123").build());
 +        userPatch.getResources().add(new StringPatchItem.Builder().
 +                operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_WS2).build());
 +
 +        try {
 +            userTO = updateUser(userPatch);
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType());
 +        }
 +
 +        // 3. update assigning a resource NOT forcing mandatory constraints
 +        // AND primary: must fail with PropagationException
 +        userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().value("newPassword123").build());
 +        userPatch.getResources().add(new StringPatchItem.Builder().
 +                operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_WS1).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO.getPropagationStatusTOs().get(0).getFailureReason());
 +
 +        // 4. update assigning a resource NOT forcing mandatory constraints
 +        // BUT not primary: must succeed
 +        userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().value("newPassword123456").build());
 +        userPatch.getResources().add(new StringPatchItem.Builder().
 +                operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_CSV).build());
 +
 +        updateUser(userPatch);
 +    }
 +
 +    @Test
 +    public void enforceMandatoryCondition() {
 +        UserTO userTO = getUniqueSampleTO("enforce@apache.org");
 +        userTO.getResources().add(RESOURCE_NAME_WS2);
 +        userTO.setPassword("newPassword12");
 +
 +        AttrTO type = null;
 +        for (AttrTO attr : userTO.getPlainAttrs()) {
 +            if ("type".equals(attr.getSchema())) {
 +                type = attr;
 +            }
 +        }
 +        assertNotNull(type);
 +        userTO.getPlainAttrs().remove(type);
 +
 +        try {
 +            userTO = createUser(userTO);
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType());
 +        }
 +
 +        userTO.getPlainAttrs().add(type);
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +    }
 +
 +    @Test
 +    public void enforceMandatoryConditionOnDerived() {
 +        ResourceTO resourceTO = resourceService.read(RESOURCE_NAME_CSV);
 +        assertNotNull(resourceTO);
 +        resourceTO.setKey("resource-csv-enforcing");
 +        resourceTO.setEnforceMandatoryCondition(true);
 +
 +        Response response = resourceService.create(resourceTO);
 +        resourceTO = getObject(response.getLocation(), ResourceService.class, ResourceTO.class);
 +        assertNotNull(resourceTO);
 +
 +        UserTO userTO = getUniqueSampleTO("syncope222@apache.org");
 +        userTO.getResources().add(resourceTO.getKey());
 +        userTO.setPassword("newPassword12");
 +
 +        try {
 +            userTO = createUser(userTO);
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType());
 +        }
 +
 +        userTO.getAuxClasses().add("csv");
 +        userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +        assertEquals(Collections.singleton("resource-csv-enforcing"), userTO.getResources());
 +    }
 +
 +    @Test
 +    public void createUserWithDbPropagation() {
 +        UserTO userTO = getUniqueSampleTO("yyy@yyy.yyy");
 +        userTO.getResources().add(RESOURCE_NAME_TESTDB);
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +        assertEquals(1, userTO.getPropagationStatusTOs().size());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +    }
 +
 +    @Test(expected = SyncopeClientException.class)
 +    public void createWithInvalidPassword() {
 +        UserTO userTO = getSampleTO("invalidpasswd@syncope.apache.org");
 +        userTO.setPassword("pass");
 +        createUser(userTO);
 +    }
 +
 +    @Test(expected = SyncopeClientException.class)
 +    public void createWithInvalidUsername() {
 +        UserTO userTO = getSampleTO("invalidusername@syncope.apache.org");
 +        userTO.setUsername("us");
 +        userTO.setRealm("/odd");
 +
 +        createUser(userTO);
 +    }
 +
 +    @Test(expected = SyncopeClientException.class)
 +    public void createWithInvalidPasswordByRes() {
 +        UserTO userTO = getSampleTO("invalidPwdByRes@passwd.com");
 +
 +        // configured to be minLength=16
 +        userTO.setPassword("password1");
 +        userTO.getResources().add(RESOURCE_NAME_NOPROPAGATION);
 +        createUser(userTO);
 +    }
 +
 +    @Test(expected = SyncopeClientException.class)
 +    public void createWithInvalidPasswordByGroup() {
 +        UserTO userTO = getSampleTO("invalidPwdByGroup@passwd.com");
 +
 +        // configured to be minLength=16
 +        userTO.setPassword("password1");
 +
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(8L).build());
 +
 +        createUser(userTO);
 +    }
 +
 +    @Test(expected = SyncopeClientException.class)
 +    public void createWithException() {
 +        UserTO newUserTO = new UserTO();
 +        newUserTO.getPlainAttrs().add(attrTO("userId", "userId@nowhere.org"));
 +        createUser(newUserTO);
 +    }
 +
 +    @Test
 +    public void create() {
 +        // get task list
 +        PagedResult<PropagationTaskTO> tasks = taskService.list(
 +                TaskType.PROPAGATION,
 +                SyncopeClient.getTaskQueryBuilder().page(1).size(1).build());
 +        assertNotNull(tasks);
 +        assertFalse(tasks.getResult().isEmpty());
 +
 +        long maxKey = tasks.getResult().iterator().next().getKey();
 +        PropagationTaskTO taskTO = taskService.read(maxKey);
 +
 +        assertNotNull(taskTO);
 +        int maxTaskExecutions = taskTO.getExecutions().size();
 +
 +        UserTO userTO = getUniqueSampleTO("a.b@c.com");
 +
 +        // add a membership
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(8L).build());
 +
 +        // add an attribute with a non-existing schema: must be ignored
 +        AttrTO attrWithInvalidSchemaTO = attrTO("invalid schema", "a value");
 +        userTO.getPlainAttrs().add(attrWithInvalidSchemaTO);
 +
 +        // add an attribute with null value: must be ignored
 +        userTO.getPlainAttrs().add(attrTO("activationDate", null));
 +
 +        // 1. create user
 +        UserTO newUserTO = createUser(userTO);
 +
 +        assertNotNull(newUserTO);
 +
 +        // issue SYNCOPE-15
 +        assertNotNull(newUserTO.getCreationDate());
 +        assertNotNull(newUserTO.getCreator());
 +        assertNotNull(newUserTO.getLastChangeDate());
 +        assertNotNull(newUserTO.getLastModifier());
 +        assertEquals(newUserTO.getCreationDate(), newUserTO.getLastChangeDate());
 +
 +        assertFalse(newUserTO.getPlainAttrs().contains(attrWithInvalidSchemaTO));
 +
 +        // check for changePwdDate
 +        assertNotNull(newUserTO.getCreationDate());
 +
 +        // 2. check for virtual attribute value
 +        newUserTO = userService.read(newUserTO.getKey());
 +        assertNotNull(newUserTO);
 +
 +        assertNotNull(newUserTO.getVirAttrMap());
 +        assertNotNull(newUserTO.getVirAttrMap().get("virtualdata").getValues());
 +        assertFalse(newUserTO.getVirAttrMap().get("virtualdata").getValues().isEmpty());
 +        assertEquals("virtualvalue", newUserTO.getVirAttrMap().get("virtualdata").getValues().get(0));
 +
 +        // get the new task list
 +        tasks = taskService.list(
 +                TaskType.PROPAGATION,
 +                SyncopeClient.getTaskQueryBuilder().page(1).size(1).build());
 +        assertNotNull(tasks);
 +        assertFalse(tasks.getResult().isEmpty());
 +
 +        long newMaxKey = tasks.getResult().iterator().next().getKey();
 +
 +        // default configuration for ws-target-resource2:
 +        // only failed executions have to be registered
 +        // --> no more tasks/executions should be added
 +        assertEquals(newMaxKey, maxKey);
 +
 +        // get last task
 +        taskTO = taskService.read(newMaxKey);
 +
 +        assertNotNull(taskTO);
 +        assertEquals(maxTaskExecutions, taskTO.getExecutions().size());
 +
 +        // 3. verify password
 +        try {
 +            Pair<Map<String, Set<String>>, UserTO> self =
 +                    clientFactory.create(newUserTO.getUsername(), "password123").self();
 +            assertNotNull(self);
 +        } catch (AccessControlException e) {
 +            fail("Credentials should be valid and not cause AccessControlException");
 +        }
 +
 +        UserSelfService userSelfService2 = clientFactory.create(
 +                newUserTO.getUsername(), "passwordXX").getService(UserSelfService.class);
 +        try {
 +            userSelfService2.read();
 +            fail("Credentials are invalid, thus request should raise AccessControlException");
 +        } catch (AccessControlException e) {
 +            assertNotNull(e);
 +        }
 +
 +        // 4. try (and fail) to create another user with same (unique) values
 +        userTO = getSampleTO(userTO.getUsername());
 +        AttrTO userIdAttr = userTO.getPlainAttrMap().get("userId");
 +        userIdAttr.getValues().clear();
 +        userIdAttr.getValues().add("a.b@c.com");
 +
 +        try {
 +            createUser(userTO);
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.GenericPersistence, e.getType());
 +        }
 +    }
 +
 +    @Test
 +    public void createWithRequiredValueMissing() {
 +        UserTO userTO = getSampleTO("a.b@c.it");
 +
 +        AttrTO type = userTO.getPlainAttrMap().get("type");
 +        userTO.getPlainAttrs().remove(type);
 +
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(8L).build());
 +
 +        // 1. create user without type (mandatory by UserSchema)
 +        try {
 +            createUser(userTO);
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType());
 +        }
 +
 +        userTO.getPlainAttrs().add(attrTO("type", "F"));
 +
 +        AttrTO surname = userTO.getPlainAttrMap().get("surname");
 +        userTO.getPlainAttrs().remove(surname);
 +
 +        // 2. create user without surname (mandatory when type == 'F')
 +        try {
 +            createUser(userTO);
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType());
 +        }
 +    }
 +
 +    @Test
 +    public void delete() {
 +        try {
 +            userService.delete(0L);
 +        } catch (SyncopeClientException e) {
 +            assertEquals(Response.Status.NOT_FOUND, e.getType().getResponseStatus());
 +        }
 +
 +        UserTO userTO = getSampleTO("qqgf.z@nn.com");
 +
 +        // specify a propagation
 +        userTO.getResources().add(RESOURCE_NAME_TESTDB);
 +
 +        userTO = createUser(userTO);
 +
 +        long key = userTO.getKey();
 +
 +        userTO = deleteUser(key);
 +
 +        assertNotNull(userTO);
 +        assertEquals(key, userTO.getKey());
 +        assertTrue(userTO.getPlainAttrs().isEmpty());
 +
 +        // check for propagation result
 +        assertFalse(userTO.getPropagationStatusTOs().isEmpty());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +
 +        try {
 +            userService.delete(userTO.getKey());
 +        } catch (SyncopeClientException e) {
 +            assertEquals(Response.Status.NOT_FOUND, e.getType().getResponseStatus());
 +        }
 +    }
 +
 +    @Test
 +    public void deleteByUsername() {
 +        UserTO userTO = getSampleTO("delete.by.username@apache.org");
 +
 +        // specify a propagation
 +        userTO.getResources().add(RESOURCE_NAME_TESTDB);
 +
 +        userTO = createUser(userTO);
 +
 +        long id = userTO.getKey();
 +        userTO = userService.read(id);
 +        userTO = deleteUser(userTO.getKey());
 +
 +        assertNotNull(userTO);
 +        assertEquals(id, userTO.getKey());
 +        assertTrue(userTO.getPlainAttrs().isEmpty());
 +
 +        // check for propagation result
 +        assertFalse(userTO.getPropagationStatusTOs().isEmpty());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +
 +        try {
 +            userService.read(userTO.getKey());
 +        } catch (SyncopeClientException e) {
 +            assertEquals(Response.Status.NOT_FOUND, e.getType().getResponseStatus());
 +        }
 +    }
 +
 +    @Test
 +    public void list() {
 +        PagedResult<UserTO> users = userService.list(
 +                SyncopeClient.getAnyListQueryBuilder().realm(SyncopeConstants.ROOT_REALM).build());
 +        assertNotNull(users);
 +        assertFalse(users.getResult().isEmpty());
 +
 +        for (UserTO user : users.getResult()) {
 +            assertNotNull(user);
 +        }
 +    }
 +
 +    @Test
 +    public void paginatedList() {
 +        PagedResult<UserTO> users = userService.list(
 +                SyncopeClient.getAnyListQueryBuilder().realm(SyncopeConstants.ROOT_REALM).page(1).size(2).build());
 +        assertNotNull(users);
 +        assertFalse(users.getResult().isEmpty());
 +        assertEquals(2, users.getResult().size());
 +
 +        for (UserTO user : users.getResult()) {
 +            assertNotNull(user);
 +        }
 +
 +        users = userService.list(SyncopeClient.getAnyListQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
 +                page(2).size(2).build());
 +        assertNotNull(users);
 +        assertEquals(2, users.getPage());
 +        assertEquals(2, users.getResult().size());
 +
 +        users = userService.list(SyncopeClient.getAnyListQueryBuilder().realm(SyncopeConstants.ROOT_REALM).
 +                page(100).size(2).build());
 +        assertNotNull(users);
 +        assertTrue(users.getResult().isEmpty());
 +    }
 +
 +    @Test
 +    public void read() {
 +        UserTO userTO = userService.read(1L);
 +
 +        assertNotNull(userTO);
 +        assertNotNull(userTO.getPlainAttrs());
 +        assertFalse(userTO.getPlainAttrs().isEmpty());
 +    }
 +
 +    @Test
 +    public void readWithMailAddressAsUserName() {
 +        UserTO userTO = createUser(getUniqueSampleTO("mail@domain.org"));
 +        userTO = userService.read(userTO.getKey());
 +        assertNotNull(userTO);
 +    }
 +
 +    @Test
 +    public void updateWithouPassword() {
 +        UserTO userTO = getUniqueSampleTO("updatewithout@password.com");
 +
 +        userTO = createUser(userTO);
 +
 +        assertNotNull(userTO);
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.getDerAttrs().add(new AttrPatch.Builder().operation(PatchOperation.DELETE).
 +                attrTO(new AttrTO.Builder().schema("cn").build()).
 +                build());
 +
 +        userTO = updateUser(userPatch);
 +
 +        assertNotNull(userTO);
 +        assertNotNull(userTO.getDerAttrMap());
 +        assertFalse(userTO.getDerAttrMap().containsKey("cn"));
 +    }
 +
 +    @Test(expected = SyncopeClientException.class)
 +    public void updateInvalidPassword() {
 +        UserTO userTO = getSampleTO("updateinvalid@password.com");
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().value("pass").build());
 +
 +        userService.update(userPatch);
 +    }
 +
 +    @Test(expected = SyncopeClientException.class)
 +    public void updateSamePassword() {
 +        UserTO userTO = getUniqueSampleTO("updatesame@password.com");
 +        userTO.setRealm("/even/two");
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().value("password123").build());
 +
 +        userService.update(userPatch);
 +    }
 +
 +    @Test
 +    public void update() {
 +        UserTO userTO = getUniqueSampleTO("g.h@t.com");
 +
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(8L).build());
 +
 +        userTO = createUser(userTO);
 +
 +        assertFalse(userTO.getDerAttrs().isEmpty());
 +        assertEquals(1, userTO.getMemberships().size());
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().value("new2Password").build());
 +
 +        String newUserId = getUUIDString() + "t.w@spre.net";
 +        userPatch.getPlainAttrs().add(attrAddReplacePatch("userId", newUserId));
 +
 +        String newFullName = getUUIDString() + "g.h@t.com";
 +        userPatch.getPlainAttrs().add(attrAddReplacePatch("fullname", newFullName));
 +
 +        userPatch.getDerAttrs().add(new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).
 +                attrTO(new AttrTO.Builder().schema("cn").build()).build());
 +        userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.ADD_REPLACE).
 +                membershipTO(new MembershipTO.Builder().group(8L).build()).build());
 +        userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.ADD_REPLACE).
 +                membershipTO(userTO.getMemberships().get(0)).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO);
 +
 +        // issue SYNCOPE-15
 +        assertNotNull(userTO.getCreationDate());
 +        assertNotNull(userTO.getCreator());
 +        assertNotNull(userTO.getLastChangeDate());
 +        assertNotNull(userTO.getLastModifier());
 +        assertTrue(userTO.getCreationDate().before(userTO.getLastChangeDate()));
 +
 +        assertEquals(1, userTO.getMemberships().size());
 +        assertFalse(userTO.getDerAttrs().isEmpty());
 +
 +        AttrTO userIdAttr = userTO.getPlainAttrMap().get("userId");
 +        assertEquals(Collections.singletonList(newUserId), userIdAttr.getValues());
 +
 +        AttrTO fullNameAttr = userTO.getPlainAttrMap().get("fullname");
 +        assertEquals(Collections.singletonList(newFullName), fullNameAttr.getValues());
 +    }
 +
 +    @Test
 +    public void updatePasswordOnly() {
 +        int beforeTasks = taskService.list(TaskType.PROPAGATION,
 +                SyncopeClient.getTaskQueryBuilder().page(1).size(1).build()).getTotalCount();
 +        assertFalse(beforeTasks <= 0);
 +
 +        UserTO userTO = getUniqueSampleTO("pwdonly@t.com");
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(8L).build());
 +
 +        userTO = createUser(userTO);
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
-         userPatch.setPassword(new PasswordPatch.Builder().value("newPassword123").build());
++        userPatch.setPassword(new PasswordPatch.Builder().value("newPassword123").resource(RESOURCE_NAME_WS2).build());
 +
 +        userTO = updateUser(userPatch);
 +
 +        // check for changePwdDate
 +        assertNotNull(userTO.getChangePwdDate());
 +
 +        int afterTasks = taskService.list(TaskType.PROPAGATION,
 +                SyncopeClient.getTaskQueryBuilder().page(1).size(1).build()).getTotalCount();
 +        assertFalse(beforeTasks <= 0);
 +
 +        assertTrue(beforeTasks < afterTasks);
 +    }
 +
 +    @SuppressWarnings("unchecked")
 +    @Test
 +    public void verifyTaskRegistration() {
 +        // get task list
 +        PagedResult<PropagationTaskTO> tasks = taskService.list(
 +                TaskType.PROPAGATION,
 +                SyncopeClient.getTaskQueryBuilder().page(1).size(1).build());
 +        assertNotNull(tasks);
 +        assertFalse(tasks.getResult().isEmpty());
 +
 +        long maxKey = tasks.getResult().iterator().next().getKey();
 +
 +        // --------------------------------------
 +        // Create operation
 +        // --------------------------------------
 +        UserTO userTO = getUniqueSampleTO("t@p.mode");
 +
 +        // add a membership
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(8L).build());
 +
 +        // 1. create user
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +
 +        // get the new task list
 +        tasks = taskService.list(
 +                TaskType.PROPAGATION,
 +                SyncopeClient.getTaskQueryBuilder().page(1).size(1).build());
 +        assertNotNull(tasks);
 +        assertFalse(tasks.getResult().isEmpty());
 +
 +        long newMaxKey = tasks.getResult().iterator().next().getKey();
 +
 +        // default configuration for ws-target-resource2:
 +        // only failed executions have to be registered
 +        // --> no more tasks/executions should be added
 +        assertEquals(newMaxKey, maxKey);
 +
 +        // --------------------------------------
 +        // Update operation
 +        // --------------------------------------
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +
 +        userPatch.getPlainAttrs().add(attrAddReplacePatch("surname", "surname"));
 +
 +        userTO = updateUser(userPatch);
 +
 +        assertNotNull(userTO);
 +
 +        // get the new task list
 +        tasks = taskService.list(
 +                TaskType.PROPAGATION,
 +                SyncopeClient.getTaskQueryBuilder().page(1).size(1).build());
 +
 +        maxKey = newMaxKey;
 +        newMaxKey = tasks.getResult().iterator().next().getKey();
 +
 +        // default configuration for ws-target-resource2:
 +        // all update executions have to be registered
 +        assertTrue(newMaxKey > maxKey);
 +
 +        final PropagationTaskTO taskTO = taskService.read(newMaxKey);
 +
 +        assertNotNull(taskTO);
 +        assertEquals(1, taskTO.getExecutions().size());
 +
 +        // --------------------------------------
 +        // Delete operation
 +        // --------------------------------------
 +        userService.delete(userTO.getKey());
 +
 +        // get the new task list
 +        tasks = taskService.list(
 +                TaskType.PROPAGATION,
 +                SyncopeClient.getTaskQueryBuilder().page(1).size(1).build());
 +
 +        maxKey = newMaxKey;
 +        newMaxKey = tasks.getResult().iterator().next().getKey();
 +
 +        // default configuration for ws-target-resource2: no delete executions have to be registered
 +        // --> no more tasks/executions should be added
 +        assertEquals(newMaxKey, maxKey);
 +    }
 +
 +    @Test
 +    public void createActivate() {
 +        Assume.assumeTrue(ActivitiDetector.isActivitiEnabledForUsers(syncopeService));
 +
 +        UserTO userTO = getUniqueSampleTO("createActivate@syncope.apache.org");
 +
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(11L).build());
 +
 +        userTO = createUser(userTO);
 +
 +        assertNotNull(userTO);
 +        assertNotNull(userTO.getToken());
 +        assertNotNull(userTO.getTokenExpireTime());
 +
 +        assertEquals("created", userTO.getStatus());
 +
 +        StatusPatch statusPatch = new StatusPatch();
 +        statusPatch.setKey(userTO.getKey());
 +        statusPatch.setType(StatusPatchType.ACTIVATE);
 +        statusPatch.setToken(userTO.getToken());
 +        userTO = userService.status(statusPatch).readEntity(UserTO.class);
 +
 +        assertNotNull(userTO);
 +        assertNull(userTO.getToken());
 +        assertNull(userTO.getTokenExpireTime());
 +        assertEquals("active", userTO.getStatus());
 +    }
 +
 +    @Test
 +    public void suspendReactivate() {
 +        UserTO userTO = getUniqueSampleTO("suspendReactivate@syncope.apache.org");
 +
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(7L).build());
 +
 +        userTO = createUser(userTO);
 +
 +        assertNotNull(userTO);
 +        assertEquals(ActivitiDetector.isActivitiEnabledForUsers(syncopeService)
 +                ? "active"
 +                : "created", userTO.getStatus());
 +
 +        StatusPatch statusPatch = new StatusPatch();
 +        statusPatch.setKey(userTO.getKey());
 +        statusPatch.setType(StatusPatchType.SUSPEND);
 +        userTO = userService.status(statusPatch).readEntity(UserTO.class);
 +        assertNotNull(userTO);
 +        assertEquals("suspended", userTO.getStatus());
 +
 +        statusPatch = new StatusPatch();
 +        statusPatch.setKey(userTO.getKey());
 +        statusPatch.setType(StatusPatchType.REACTIVATE);
 +        userTO = userService.status(statusPatch).readEntity(UserTO.class);
 +        assertNotNull(userTO);
 +        assertEquals("active", userTO.getStatus());
 +    }
 +
 +    @Test
 +    public void suspendReactivateOnResource() {
 +        // Assert resources are present
 +        ResourceTO dbTable = resourceService.read(RESOURCE_NAME_TESTDB);
 +        assertNotNull(dbTable);
 +        ResourceTO ldap = resourceService.read(RESOURCE_NAME_LDAP);
 +        assertNotNull(ldap);
 +
 +        // Create user with reference to resources
 +        UserTO userTO = getUniqueSampleTO("suspreactonresource@syncope.apache.org");
 +        userTO.getMemberships().clear();
 +        userTO.getResources().clear();
 +        userTO.getResources().add(RESOURCE_NAME_TESTDB);
 +        userTO.getResources().add(RESOURCE_NAME_LDAP);
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +        assertEquals(ActivitiDetector.isActivitiEnabledForUsers(syncopeService)
 +                ? "active"
 +                : "created", userTO.getStatus());
 +        long userKey = userTO.getKey();
 +
 +        // Suspend with effect on syncope, ldap and db => user should be suspended in syncope and all resources
 +        StatusPatch statusPatch = new StatusPatch();
 +        statusPatch.setKey(userKey);
 +        statusPatch.setType(StatusPatchType.SUSPEND);
 +        statusPatch.setOnSyncope(true);
 +        statusPatch.getResources().add(RESOURCE_NAME_TESTDB);
 +        statusPatch.getResources().add(RESOURCE_NAME_LDAP);
 +        userTO = userService.status(statusPatch).readEntity(UserTO.class);
 +        assertNotNull(userTO);
 +        assertEquals("suspended", userTO.getStatus());
 +
 +        ConnObjectTO connObjectTO =
 +                resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userKey);
 +        assertFalse(getBooleanAttribute(connObjectTO, OperationalAttributes.ENABLE_NAME));
 +
 +        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), userKey);
 +        assertNotNull(connObjectTO);
 +
 +        // Suspend and reactivate only on ldap => db and syncope should still show suspended
 +        statusPatch = new StatusPatch();
 +        statusPatch.setKey(userKey);
 +        statusPatch.setType(StatusPatchType.SUSPEND);
 +        statusPatch.setOnSyncope(false);
 +        statusPatch.getResources().add(RESOURCE_NAME_LDAP);
 +        userService.status(statusPatch);
 +        statusPatch.setType(StatusPatchType.REACTIVATE);
 +        userTO = userService.status(statusPatch).readEntity(UserTO.class);
 +        assertNotNull(userTO);
 +        assertEquals("suspended", userTO.getStatus());
 +
 +        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userKey);
 +        assertFalse(getBooleanAttribute(connObjectTO, OperationalAttributes.ENABLE_NAME));
 +
 +        // Reactivate on syncope and db => syncope and db should show the user as active
 +        statusPatch = new StatusPatch();
 +        statusPatch.setKey(userKey);
 +        statusPatch.setType(StatusPatchType.REACTIVATE);
 +        statusPatch.setOnSyncope(true);
 +        statusPatch.getResources().add(RESOURCE_NAME_TESTDB);
 +
 +        userTO = userService.status(statusPatch).readEntity(UserTO.class);
 +        assertNotNull(userTO);
 +        assertEquals("active", userTO.getStatus());
 +
 +        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userKey);
 +        assertTrue(getBooleanAttribute(connObjectTO, OperationalAttributes.ENABLE_NAME));
 +    }
 +
 +    @Test
 +    public void updateMultivalueAttribute() {
 +        UserTO userTO = getUniqueSampleTO("multivalue@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getVirAttrs().clear();
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +
 +        AttrTO loginDate = userTO.getPlainAttrMap().get("loginDate");
 +        assertNotNull(loginDate);
 +        assertEquals(1, loginDate.getValues().size());
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +
 +        loginDate.getValues().add("2000-01-01");
 +        userPatch.getPlainAttrs().add(new AttrPatch.Builder().
 +                operation(PatchOperation.ADD_REPLACE).attrTO(loginDate).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO);
 +
 +        loginDate = userTO.getPlainAttrMap().get("loginDate");
 +        assertNotNull(loginDate);
 +        assertEquals(2, loginDate.getValues().size());
 +    }
 +
 +    @Test(expected = EmptyResultDataAccessException.class)
 +    public void issue213() {
 +        UserTO userTO = getUniqueSampleTO("issue213@syncope.apache.org");
 +        userTO.getResources().add(RESOURCE_NAME_TESTDB);
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +        assertEquals(1, userTO.getResources().size());
 +
 +        JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
 +
 +        String username = jdbcTemplate.queryForObject("SELECT id FROM test WHERE id=?", String.class,
 +                userTO.getUsername());
 +
 +        assertEquals(userTO.getUsername(), username);
 +
 +        UserPatch userPatch = new UserPatch();
 +
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.getResources().add(
 +                new StringPatchItem.Builder().operation(PatchOperation.DELETE).value(RESOURCE_NAME_TESTDB).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertTrue(userTO.getResources().isEmpty());
 +
 +        jdbcTemplate.queryForObject("SELECT id FROM test WHERE id=?", String.class, userTO.getUsername());
 +    }
 +
 +    @Test
 +    public void issue234() {
 +        UserTO inUserTO = getUniqueSampleTO("issue234@syncope.apache.org");
 +        inUserTO.getResources().add(RESOURCE_NAME_LDAP);
 +
 +        UserTO userTO = createUser(inUserTO);
 +        assertNotNull(userTO);
 +
 +        UserPatch userPatch = new UserPatch();
 +
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setUsername(new StringReplacePatchItem.Builder().value("1" + userTO.getUsername()).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO);
 +        assertEquals("1" + inUserTO.getUsername(), userTO.getUsername());
 +    }
 +
 +    @Test
 +    public void issue270() {
 +        // 1. create a new user without virtual attributes
 +        UserTO original = getUniqueSampleTO("issue270@syncope.apache.org");
 +        // be sure to remove all virtual attributes
 +        original.getVirAttrs().clear();
 +
 +        original = createUser(original);
 +
 +        assertNotNull(original);
 +
 +        assertTrue(original.getVirAttrs().isEmpty());
 +
 +        UserTO toBeUpdated = userService.read(original.getKey());
 +
 +        AttrTO virtual = attrTO("virtualdata", "virtualvalue");
 +        toBeUpdated.getVirAttrs().add(virtual);
 +
 +        // 2. try to update by adding a resource, but no password: must fail
 +        UserPatch userPatch = AnyOperations.diff(toBeUpdated, original, false);
 +        assertNotNull(userPatch);
 +
 +        toBeUpdated = updateUser(userPatch);
 +        assertNotNull(toBeUpdated);
 +
 +        assertFalse(toBeUpdated.getVirAttrs().isEmpty());
 +        assertNotNull(toBeUpdated.getVirAttrs().iterator().next());
 +
 +        assertEquals(virtual.getSchema(), toBeUpdated.getVirAttrs().iterator().next().getSchema());
 +    }
 +
 +    @Test
 +    public final void issue280() {
 +        UserTO userTO = getUniqueSampleTO("issue280@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().onSyncope(false).
 +                resource(RESOURCE_NAME_TESTDB).value("123password").build());
 +        userPatch.getResources().add(new StringPatchItem.Builder().
 +                operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_TESTDB).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO);
 +
 +        List<PropagationStatus> propagations = userTO.getPropagationStatusTOs();
 +        assertNotNull(propagations);
 +        assertEquals(1, propagations.size());
 +
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, propagations.get(0).getStatus());
 +
 +        String resource = propagations.get(0).getResource();
 +        assertEquals(RESOURCE_NAME_TESTDB, resource);
 +    }
 +
 +    @Test
 +    public void issue281() {
 +        UserTO userTO = getUniqueSampleTO("issue281@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getResources().add(RESOURCE_NAME_CSV);
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +
 +        List<PropagationStatus> propagations = userTO.getPropagationStatusTOs();
 +        assertNotNull(propagations);
 +        assertEquals(1, propagations.size());
 +
 +        assertNotEquals(PropagationTaskExecStatus.SUCCESS, propagations.get(0).getStatus());
 +
 +        String resource = propagations.get(0).getResource();
 +        assertEquals(RESOURCE_NAME_CSV, resource);
 +    }
 +
 +    @Test
 +    public void issue288() {
 +        UserTO userTO = getSampleTO("issue288@syncope.apache.org");
 +        userTO.getPlainAttrs().add(attrTO("aLong", "STRING"));
 +
 +        try {
 +            createUser(userTO);
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.InvalidValues, e.getType());
 +        }
 +    }
 +
 +    @Test
 +    public void groupAttrPropagation() {
 +        UserTO userTO = getUniqueSampleTO("checkGroupAttrPropagation@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getVirAttrs().clear();
 +
 +        userTO.getAuxClasses().add("csv");
 +        userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(1L).build());
 +
 +        userTO.getResources().add(RESOURCE_NAME_CSV);
 +
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +        assertNotNull(actual.getDerAttrMap().get("csvuserid"));
 +
 +        ConnObjectTO connObjectTO =
 +                resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +        assertNotNull(connObjectTO);
 +        assertEquals("sx-dx", connObjectTO.getPlainAttrMap().get("THEIRGROUP").getValues().get(0));
 +    }
 +
 +    @Test
 +    public void noContent() throws IOException {
 +        SyncopeClient noContentclient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
 +        UserService noContentService = noContentclient.prefer(UserService.class, Preference.RETURN_NO_CONTENT);
 +
 +        UserTO user = getUniqueSampleTO("nocontent@syncope.apache.org");
 +
 +        Response response = noContentService.create(user, true);
 +        assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
 +        assertEquals(Preference.RETURN_NO_CONTENT.toString(), response.getHeaderString(RESTHeaders.PREFERENCE_APPLIED));
 +        assertEquals(StringUtils.EMPTY, IOUtils.toString((InputStream) response.getEntity()));
 +
 +        user = getObject(response.getLocation(), UserService.class, UserTO.class);
 +        assertNotNull(user);
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(user.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().value("password321").build());
 +
 +        response = noContentService.update(userPatch);
 +        assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
 +        assertEquals(Preference.RETURN_NO_CONTENT.toString(), response.getHeaderString(RESTHeaders.PREFERENCE_APPLIED));
 +        assertEquals(StringUtils.EMPTY, IOUtils.toString((InputStream) response.getEntity()));
 +
 +        response = noContentService.delete(user.getKey());
 +        assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
 +        assertEquals(Preference.RETURN_NO_CONTENT.toString(), response.getHeaderString(RESTHeaders.PREFERENCE_APPLIED));
 +        assertEquals(StringUtils.EMPTY, IOUtils.toString((InputStream) response.getEntity()));
 +    }
 +
 +    @Test
 +    public void customPolicyRules() {
 +        // Using custom policy rules with application/xml requires to overwrite
 +        // org.apache.syncope.common.lib.policy.AbstractAccountRuleConf's and / or
 +        // org.apache.syncope.common.lib.policy.AbstractPasswordRuleConf's
 +        // @XmlSeeAlso - the power of JAXB :-/
 +        Assume.assumeTrue(MediaType.APPLICATION_JSON_TYPE.equals(clientFactory.getContentType().getMediaType()));
 +
 +        AccountPolicyTO accountPolicy = new AccountPolicyTO();
 +        accountPolicy.setDescription("Account Policy with custom rules");
 +        accountPolicy.getRuleConfs().add(new TestAccountRuleConf());
 +        accountPolicy = createPolicy(accountPolicy);
 +        assertNotNull(accountPolicy);
 +
 +        PasswordPolicyTO passwordPolicy = new PasswordPolicyTO();
 +        passwordPolicy.setDescription("Password Policy with custom rules");
 +        passwordPolicy.getRuleConfs().add(new TestPasswordRuleConf());
 +        passwordPolicy = createPolicy(passwordPolicy);
 +        assertNotNull(passwordPolicy);
 +
 +        RealmTO realm = realmService.list("/even/two").get(0);
 +        Long oldAccountPolicy = realm.getAccountPolicy();
 +        realm.setAccountPolicy(accountPolicy.getKey());
 +        Long oldPasswordPolicy = realm.getPasswordPolicy();
 +        realm.setPasswordPolicy(passwordPolicy.getKey());
 +        realmService.update(realm);
 +
 +        try {
 +            UserTO user = getUniqueSampleTO("custompolicyrules@syncope.apache.org");
 +            user.setRealm(realm.getFullPath());
 +            try {
 +                createUser(user);
 +                fail();
 +            } catch (SyncopeClientException e) {
 +                assertEquals(ClientExceptionType.InvalidUser, e.getType());
 +                assertTrue(e.getElements().iterator().next().startsWith("InvalidPassword"));
 +            }
 +
 +            user.setPassword(user.getPassword() + "XXX");
 +            try {
 +                createUser(user);
 +                fail();
 +            } catch (SyncopeClientException e) {
 +                assertEquals(ClientExceptionType.InvalidUser, e.getType());
 +                assertTrue(e.getElements().iterator().next().startsWith("InvalidUsername"));
 +            }
 +
 +            user.setUsername("YYY" + user.getUsername());
 +            user = createUser(user);
 +            assertNotNull(user);
 +        } finally {
 +            realm.setAccountPolicy(oldAccountPolicy);
 +            realm.setPasswordPolicy(oldPasswordPolicy);
 +            realmService.update(realm);
 +
 +            policyService.delete(passwordPolicy.getKey());
 +            policyService.delete(accountPolicy.getKey());
 +        }
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE108() {
 +        UserTO userTO = getUniqueSampleTO("syncope108@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getVirAttrs().clear();
 +        userTO.getAuxClasses().add("csv");
 +        userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(12L).build());
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(13L).build());
 +
 +        userTO.getResources().add(RESOURCE_NAME_CSV);
 +
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +        assertEquals(2, actual.getMemberships().size());
 +        assertEquals(1, actual.getResources().size());
 +
 +        ConnObjectTO connObjectTO =
 +                resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +        assertNotNull(connObjectTO);
 +
 +        // -----------------------------------
 +        // Remove the first membership: de-provisioning shouldn't happen
 +        // -----------------------------------
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(actual.getKey());
 +
 +        userPatch.getMemberships().add(new MembershipPatch.Builder().
 +                operation(PatchOperation.DELETE).membershipTO(actual.getMemberships().get(0)).build());
 +
 +        actual = updateUser(userPatch);
 +        assertNotNull(actual);
 +        assertEquals(1, actual.getMemberships().size());
 +
 +        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +        assertNotNull(connObjectTO);
 +        // -----------------------------------
 +
 +        // -----------------------------------
 +        // Remove the resource assigned directly: de-provisioning shouldn't happen
 +        // -----------------------------------
 +        userPatch = new UserPatch();
 +        userPatch.setKey(actual.getKey());
 +
 +        userPatch.getResources().add(new StringPatchItem.Builder().operation(PatchOperation.DELETE).
 +                value(actual.getResources().iterator().next()).build());
 +
 +        actual = updateUser(userPatch);
 +        assertNotNull(actual);
 +        assertEquals(1, actual.getMemberships().size());
 +        assertFalse(actual.getResources().isEmpty());
 +
 +        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +        assertNotNull(connObjectTO);
 +        // -----------------------------------
 +
 +        // -----------------------------------
 +        // Remove the first membership: de-provisioning should happen
 +        // -----------------------------------
 +        userPatch = new UserPatch();
 +        userPatch.setKey(actual.getKey());
 +
 +        userPatch.getMemberships().add(new MembershipPatch.Builder().
 +                operation(PatchOperation.DELETE).membershipTO(actual.getMemberships().get(0)).build());
 +
 +        actual = updateUser(userPatch);
 +        assertNotNull(actual);
 +        assertTrue(actual.getMemberships().isEmpty());
 +        assertTrue(actual.getResources().isEmpty());
 +
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +            fail("Read should not succeeed");
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.NotFound, e.getType());
 +        }
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE185() {
 +        // 1. create user with LDAP resource, succesfully propagated
 +        UserTO userTO = getSampleTO("syncope185@syncope.apache.org");
 +        userTO.getVirAttrs().clear();
 +        userTO.getResources().add(RESOURCE_NAME_LDAP);
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +        assertFalse(userTO.getPropagationStatusTOs().isEmpty());
 +        assertEquals(RESOURCE_NAME_LDAP, userTO.getPropagationStatusTOs().get(0).getResource());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +
 +        // 2. delete this user
 +        userService.delete(userTO.getKey());
 +
 +        // 3. try (and fail) to find this user on the external LDAP resource
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), userTO.getKey());
 +            fail("This entry should not be present on this resource");
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.NotFound, e.getType());
 +        }
 +    }
 +
 +    @Test()
 +    public void issueSYNCOPE51() {
 +        AttrTO defaultCA = configurationService.get("password.cipher.algorithm");
 +        final String originalCAValue = defaultCA.getValues().get(0);
 +        defaultCA.getValues().set(0, "MD5");
 +        configurationService.set(defaultCA);
 +
 +        AttrTO newCA = configurationService.get(defaultCA.getSchema());
 +        assertEquals(defaultCA, newCA);
 +
 +        UserTO userTO = getSampleTO("syncope51@syncope.apache.org");
 +        userTO.setPassword("password");
 +
 +        try {
 +            createUser(userTO);
 +            fail("Create user should not succeed");
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.NotFound, e.getType());
 +            assertTrue(e.getElements().iterator().next().contains("MD5"));
 +        }
 +
 +        defaultCA.getValues().set(0, originalCAValue);
 +        configurationService.set(defaultCA);
 +
 +        AttrTO oldCA = configurationService.get(defaultCA.getSchema());
 +        assertEquals(defaultCA, oldCA);
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE267() {
 +        // ----------------------------------
 +        // create user and check virtual attribute value propagation
 +        // ----------------------------------
 +        UserTO userTO = getUniqueSampleTO("syncope267@apache.org");
 +        userTO.getResources().clear();
 +        userTO.getResources().add(RESOURCE_NAME_DBVIRATTR);
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +        assertFalse(userTO.getPropagationStatusTOs().isEmpty());
 +        assertEquals(RESOURCE_NAME_DBVIRATTR, userTO.getPropagationStatusTOs().get(0).getResource());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +
 +        ConnObjectTO connObjectTO =
 +                resourceService.readConnObject(RESOURCE_NAME_DBVIRATTR, AnyTypeKind.USER.name(), userTO.getKey());
 +        assertNotNull(connObjectTO);
 +        assertEquals("virtualvalue", connObjectTO.getPlainAttrMap().get("USERNAME").getValues().get(0));
 +        // ----------------------------------
 +
 +        userTO = userService.read(userTO.getKey());
 +
 +        assertNotNull(userTO);
 +        assertEquals(1, userTO.getVirAttrs().size());
 +        assertEquals("virtualvalue", userTO.getVirAttrs().iterator().next().getValues().get(0));
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE266() {
 +        UserTO userTO = getUniqueSampleTO("syncope266@apache.org");
 +        userTO.getResources().clear();
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +
 +        // this resource has not a mapping for Password
 +        userPatch.getResources().add(new StringPatchItem.Builder().
 +                operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_UPDATE).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO);
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE279() {
 +        UserTO userTO = getUniqueSampleTO("syncope279@apache.org");
 +        userTO.getResources().clear();
 +        userTO.getResources().add(RESOURCE_NAME_TIMEOUT);
 +        userTO = createUser(userTO);
 +        assertEquals(RESOURCE_NAME_TIMEOUT, userTO.getPropagationStatusTOs().get(0).getResource());
 +        assertNotNull(userTO.getPropagationStatusTOs().get(0).getFailureReason());
 +        assertEquals(PropagationTaskExecStatus.FAILURE, userTO.getPropagationStatusTOs().get(0).getStatus());
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE122() {
 +        // 1. create user on testdb and testdb2
 +        UserTO userTO = getUniqueSampleTO("syncope122@apache.org");
 +        userTO.getResources().clear();
 +
 +        userTO.getResources().add(RESOURCE_NAME_TESTDB);
 +        userTO.getResources().add(RESOURCE_NAME_TESTDB2);
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +        assertTrue(userTO.getResources().contains(RESOURCE_NAME_TESTDB));
 +        assertTrue(userTO.getResources().contains(RESOURCE_NAME_TESTDB2));
 +
 +        final String pwdOnSyncope = userTO.getPassword();
 +
 +        ConnObjectTO userOnDb = resourceService.readConnObject(
 +                RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userTO.getKey());
 +        final AttrTO pwdOnTestDbAttr = userOnDb.getPlainAttrMap().get(OperationalAttributes.PASSWORD_NAME);
 +        assertNotNull(pwdOnTestDbAttr);
 +        assertNotNull(pwdOnTestDbAttr.getValues());
 +        assertFalse(pwdOnTestDbAttr.getValues().isEmpty());
 +        final String pwdOnTestDb = pwdOnTestDbAttr.getValues().iterator().next();
 +
 +        ConnObjectTO userOnDb2 = resourceService.readConnObject(
 +                RESOURCE_NAME_TESTDB2, AnyTypeKind.USER.name(), userTO.getKey());
 +        final AttrTO pwdOnTestDb2Attr = userOnDb2.getPlainAttrMap().get(OperationalAttributes.PASSWORD_NAME);
 +        assertNotNull(pwdOnTestDb2Attr);
 +        assertNotNull(pwdOnTestDb2Attr.getValues());
 +        assertFalse(pwdOnTestDb2Attr.getValues().isEmpty());
 +        final String pwdOnTestDb2 = pwdOnTestDb2Attr.getValues().iterator().next();
 +
 +        // 2. request to change password only on testdb (no Syncope, no testdb2)
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().value(getUUIDString()).onSyncope(false).
 +                resource(RESOURCE_NAME_TESTDB).build());
 +
 +        userTO = updateUser(userPatch);
 +
 +        // 3a. Chech that only a single propagation took place
 +        assertNotNull(userTO.getPropagationStatusTOs());
 +        assertEquals(1, userTO.getPropagationStatusTOs().size());
 +        assertEquals(RESOURCE_NAME_TESTDB, userTO.getPropagationStatusTOs().iterator().next().getResource());
 +
 +        // 3b. verify that password hasn't changed on Syncope
 +        assertEquals(pwdOnSyncope, userTO.getPassword());
 +
 +        // 3c. verify that password *has* changed on testdb
 +        userOnDb = resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userTO.getKey());
 +        final AttrTO pwdOnTestDbAttrAfter = userOnDb.getPlainAttrMap().get(OperationalAttributes.PASSWORD_NAME);
 +        assertNotNull(pwdOnTestDbAttrAfter);
 +        assertNotNull(pwdOnTestDbAttrAfter.getValues());
 +        assertFalse(pwdOnTestDbAttrAfter.getValues().isEmpty());
 +        assertNotEquals(pwdOnTestDb, pwdOnTestDbAttrAfter.getValues().iterator().next());
 +
 +        // 3d. verify that password hasn't changed on testdb2
 +        userOnDb2 = resourceService.readConnObject(RESOURCE_NAME_TESTDB2, AnyTypeKind.USER.name(), userTO.getKey());
 +        final AttrTO pwdOnTestDb2AttrAfter = userOnDb2.getPlainAttrMap().get(OperationalAttributes.PASSWORD_NAME);
 +        assertNotNull(pwdOnTestDb2AttrAfter);
 +        assertNotNull(pwdOnTestDb2AttrAfter.getValues());
 +        assertFalse(pwdOnTestDb2AttrAfter.getValues().isEmpty());
 +        assertEquals(pwdOnTestDb2, pwdOnTestDb2AttrAfter.getValues().iterator().next());
 +    }
 +
 +    @Test
 +    public void isseSYNCOPE136AES() {
 +        // 1. read configured cipher algorithm in order to be able to restore it at the end of test
 +        AttrTO pwdCipherAlgo = configurationService.get("password.cipher.algorithm");
 +        final String origpwdCipherAlgo = pwdCipherAlgo.getValues().get(0);
 +
 +        // 2. set AES password cipher algorithm
 +        pwdCipherAlgo.getValues().set(0, "AES");
 +        configurationService.set(pwdCipherAlgo);
 +
 +        try {
 +            // 3. create user with no resources
 +            UserTO userTO = getUniqueSampleTO("syncope136_AES@apache.org");
 +            userTO.getResources().clear();
 +
 +            userTO = createUser(userTO);
 +            assertNotNull(userTO);
 +
 +            // 4. update user, assign a propagation primary resource but don't provide any password
 +            UserPatch userPatch = new UserPatch();
 +            userPatch.setKey(userTO.getKey());
 +            userPatch.getResources().add(new StringPatchItem.Builder().
 +                    operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_WS1).build());
 +            userPatch.setPassword(new PasswordPatch.Builder().onSyncope(false).resource(RESOURCE_NAME_WS1).build());
 +
 +            userTO = updateUser(userPatch);
 +            assertNotNull(userTO);
 +
 +            // 5. verify that propagation was successful
 +            List<PropagationStatus> props = userTO.getPropagationStatusTOs();
 +            assertNotNull(props);
 +            assertEquals(1, props.size());
 +            PropagationStatus prop = props.iterator().next();
 +            assertNotNull(prop);
 +            assertEquals(RESOURCE_NAME_WS1, prop.getResource());
 +            assertEquals(PropagationTaskExecStatus.SUCCESS, prop.getStatus());
 +        } finally {
 +            // restore initial cipher algorithm
 +            pwdCipherAlgo.getValues().set(0, origpwdCipherAlgo);
 +            configurationService.set(pwdCipherAlgo);
 +        }
 +    }
 +
 +    @Test
 +    public void isseSYNCOPE136Random() {
 +        // 1. create user with no resources
 +        UserTO userTO = getUniqueSampleTO("syncope136_Random@apache.org");
 +        userTO.getResources().clear();
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +
 +        // 2. update user, assign a propagation primary resource but don't provide any password
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.getResources().add(new StringPatchItem.Builder().
 +                operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_LDAP).build());
 +        userPatch.setPassword(new PasswordPatch.Builder().onSyncope(false).resource(RESOURCE_NAME_LDAP).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertNotNull(userTO);
 +
 +        // 3. verify that propagation was successful
 +        List<PropagationStatus> props = userTO.getPropagationStatusTOs();
 +        assertNotNull(props);
 +        assertEquals(1, props.size());
 +        PropagationStatus prop = props.iterator().next();
 +        assertNotNull(prop);
 +        assertEquals(RESOURCE_NAME_LDAP, prop.getResource());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, prop.getStatus());
 +    }
 +
 +    @Test
 +    public void mappingPurpose() {
 +        UserTO userTO = getUniqueSampleTO("mpurpose@apache.org");
 +        userTO.getAuxClasses().add("csv");
 +
 +        AttrTO csvuserid = new AttrTO();
 +        csvuserid.setSchema("csvuserid");
 +        userTO.getDerAttrs().add(csvuserid);
 +
 +        userTO.getResources().clear();
 +        userTO.getResources().add(RESOURCE_NAME_CSV);
 +
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +
 +        ConnObjectTO connObjectTO =
 +                resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +        assertNull(connObjectTO.getPlainAttrMap().get("email"));
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE265() {
 +        for (long key = 1; key <= 5; key++) {
 +            UserPatch userPatch = new UserPatch();
 +            userPatch.setKey(key);
 +
 +            userPatch.getPlainAttrs().add(attrAddReplacePatch("type", "a type"));
 +
 +            UserTO userTO = updateUser(userPatch);
 +
 +            assertEquals("a type", userTO.getPlainAttrMap().get("type").getValues().get(0));
 +        }
 +    }
 +
 +    @Test
 +    public void bulkActions() {
 +        BulkAction bulkAction = new BulkAction();
 +
 +        for (int i = 0; i < 10; i++) {
 +            UserTO userTO = getUniqueSampleTO("bulk_" + i + "@apache.org");
 +            bulkAction.getTargets().add(String.valueOf(createUser(userTO).getKey()));
 +        }
 +
 +        // check for a fail
 +        bulkAction.getTargets().add(String.valueOf(Long.MAX_VALUE));
 +
 +        assertEquals(11, bulkAction.getTargets().size());
 +
 +        bulkAction.setType(BulkAction.Type.SUSPEND);
 +        BulkActionResult res = userService.bulk(bulkAction);
 +        assertEquals(10, res.getResultByStatus(Status.SUCCESS).size());
 +        assertEquals(1, res.getResultByStatus(Status.FAILURE).size());
 +        assertEquals("suspended", userService.read(
 +                Long.parseLong(res.getResultByStatus(Status.SUCCESS).get(3))).getStatus());
 +
 +        bulkAction.setType(BulkAction.Type.REACTIVATE);
 +        res = userService.bulk(bulkAction);
 +        assertEquals(10, res.getResultByStatus(Status.SUCCESS).size());
 +        assertEquals(1, res.getResultByStatus(Status.FAILURE).size());
 +        assertEquals("active", userService.read(
 +                Long.parseLong(res.getResultByStatus(Status.SUCCESS).get(3))).getStatus());
 +
 +        bulkAction.setType(BulkAction.Type.DELETE);
 +        res = userService.bulk(bulkAction);
 +        assertEquals(10, res.getResultByStatus(Status.SUCCESS).size());
 +        assertEquals(1, res.getResultByStatus(Status.FAILURE).size());
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE354() {
 +        // change resource-ldap group mapping for including uniqueMember (need for assertions below)
 +        ResourceTO ldap = resourceService.read(RESOURCE_NAME_LDAP);
 +        for (MappingItemTO item : ldap.getProvision(AnyTypeKind.GROUP.name()).getMapping().getItems()) {
 +            if ("description".equals(item.getExtAttrName())) {
 +                item.setExtAttrName("uniqueMember");
 +            }
 +        }
 +        resourceService.update(ldap);
 +
 +        // 1. create group with LDAP resource
 +        GroupTO groupTO = new GroupTO();
 +        groupTO.setName("SYNCOPE354-" + getUUIDString());
 +        groupTO.setRealm("/");
 +        groupTO.getResources().add(RESOURCE_NAME_LDAP);
 +
 +        groupTO = createGroup(groupTO);
 +        assertNotNull(groupTO);
 +
 +        // 2. create user with LDAP resource and membership of the above group
 +        UserTO userTO = getUniqueSampleTO("syncope354@syncope.apache.org");
 +        userTO.getResources().add(RESOURCE_NAME_LDAP);
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(groupTO.getKey()).build());
 +
 +        userTO = createUser(userTO);
 +        assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP));
 +
 +        // 3. read group on resource, check that user DN is included in uniqueMember
 +        ConnObjectTO connObj = resourceService.readConnObject(
 +                RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), groupTO.getKey());
 +        assertNotNull(connObj);
 +        assertTrue(connObj.getPlainAttrMap().get("uniqueMember").getValues().
 +                contains("uid=" + userTO.getUsername() + ",ou=people,o=isp"));
 +
 +        // 4. remove membership
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.DELETE).
 +                membershipTO(userTO.getMemberships().get(0)).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP));
 +
 +        // 5. read group on resource, check that user DN was removed from uniqueMember
 +        connObj = resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), groupTO.getKey());
 +        assertNotNull(connObj);
 +        assertFalse(connObj.getPlainAttrMap().get("uniqueMember").getValues().
 +                contains("uid=" + userTO.getUsername() + ",ou=people,o=isp"));
 +
 +        // 6. restore original resource-ldap group mapping
 +        for (MappingItemTO item : ldap.getProvision(AnyTypeKind.GROUP.name()).getMapping().getItems()) {
 +            if ("uniqueMember".equals(item.getExtAttrName())) {
 +                item.setExtAttrName("description");
 +            }
 +        }
 +        resourceService.update(ldap);
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE357() throws IOException {
 +        // 1. create group with LDAP resource
 +        GroupTO groupTO = new GroupTO();
 +        groupTO.setName("SYNCOPE357-" + getUUIDString());
 +        groupTO.setRealm("/");
 +        groupTO.getResources().add(RESOURCE_NAME_LDAP);
 +
 +        groupTO = createGroup(groupTO);
 +        assertNotNull(groupTO);
 +
 +        // 2. create user with membership of the above group
 +        UserTO userTO = getUniqueSampleTO("syncope357@syncope.apache.org");
 +        userTO.getPlainAttrs().add(attrTO("obscure", "valueToBeObscured"));
 +        userTO.getPlainAttrs().add(attrTO("photo",
 +                Base64Utility.encode(IOUtils.readBytesFromStream(getClass().getResourceAsStream("/favicon.jpg")))));
 +        userTO.getMemberships().add(new MembershipTO.Builder().group(groupTO.getKey()).build());
 +
 +        userTO = createUser(userTO);
 +        assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP));
 +        assertNotNull(userTO.getPlainAttrMap().get("obscure"));
 +        assertNotNull(userTO.getPlainAttrMap().get("photo"));
 +
 +        // 3. read user on resource
 +        ConnObjectTO connObj = resourceService.readConnObject(
 +                RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), userTO.getKey());
 +        assertNotNull(connObj);
 +        AttrTO registeredAddress = connObj.getPlainAttrMap().get("registeredAddress");
 +        assertNotNull(registeredAddress);
 +        assertEquals(userTO.getPlainAttrMap().get("obscure").getValues(), registeredAddress.getValues());
 +        AttrTO jpegPhoto = connObj.getPlainAttrMap().get("jpegPhoto");
 +        assertNotNull(jpegPhoto);
 +        assertEquals(userTO.getPlainAttrMap().get("photo").getValues(), jpegPhoto.getValues());
 +
 +        // 4. remove group
 +        groupService.delete(groupTO.getKey());
 +
 +        // 5. try to read user on resource: fail
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), userTO.getKey());
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.NotFound, e.getType());
 +        }
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE383() {
 +        // 1. create user without resources
 +        UserTO userTO = getUniqueSampleTO("syncope383@apache.org");
 +        userTO.getResources().clear();
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +
 +        // 2. assign resource without specifying a new pwd and check propagation failure
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.getResources().add(new StringPatchItem.Builder().
 +                operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_TESTDB).build());
 +        userTO = updateUser(userPatch);
 +        assertEquals(RESOURCE_NAME_TESTDB, userTO.getResources().iterator().next());
 +        assertNotEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +        assertNotNull(userTO.getPropagationStatusTOs().get(0).getFailureReason());
 +
 +        // 3. request to change password only on testdb
 +        userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().value(getUUIDString() + "abbcbcbddd123").
 +                resource(RESOURCE_NAME_TESTDB).build());
 +
 +        userTO = updateUser(userPatch);
 +        assertEquals(RESOURCE_NAME_TESTDB, userTO.getResources().iterator().next());
 +        assertEquals(PropagationTaskExecStatus.SUCCESS, userTO.getPropagationStatusTOs().get(0).getStatus());
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE402() {
 +        // 1. create an user with strict mandatory attributes only
 +        UserTO userTO = new UserTO();
 +        userTO.setRealm(SyncopeConstants.ROOT_REALM);
 +        String userId = getUUIDString() + "syncope402@syncope.apache.org";
 +        userTO.setUsername(userId);
 +        userTO.setPassword("password123");
 +
 +        userTO.getPlainAttrs().add(attrTO("userId", userId));
 +        userTO.getPlainAttrs().add(attrTO("fullname", userId));
 +        userTO.getPlainAttrs().add(attrTO("surname", userId));
 +
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +        assertTrue(userTO.getResources().isEmpty());
 +
 +        // 2. update assigning a resource NOT forcing mandatory constraints
 +        // AND primary: must fail with PropagationException
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.setPassword(new PasswordPatch.Builder().value("newPassword123").build());
 +        userPatch.getResources().add(new StringPatchItem.Builder().
 +                operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_WS1).build());
 +        userPatch.getResources().add(new StringPatchItem.Builder().
 +                operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_TESTDB).build());
 +        userTO = updateUser(userPatch);
 +
 +        List<PropagationStatus> propagationStatuses = userTO.getPropagationStatusTOs();
 +        PropagationStatus ws1PropagationStatus = null;
 +        if (propagationStatuses != null) {
 +            for (PropagationStatus propStatus : propagationStatuses) {
 +                if (RESOURCE_NAME_WS1.equals(propStatus.getResource())) {
 +                    ws1PropagationStatus = propStatus;
 +                    break;
 +                }
 +            }
 +        }
 +        assertNotNull(ws1PropagationStatus);
 +        assertEquals(RESOURCE_NAME_WS1, ws1PropagationStatus.getResource());
 +        assertNotNull(ws1PropagationStatus.getFailureReason());
 +        assertEquals(PropagationTaskExecStatus.FAILURE, ws1PropagationStatus.getStatus());
 +    }
 +
 +    @Test
 +    public void unlink() {
 +        UserTO userTO = getUniqueSampleTO("unlink@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getVirAttrs().clear();
 +        userTO.getAuxClasses().add("csv");
 +        userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +        userTO.getResources().add(RESOURCE_NAME_CSV);
 +
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +        assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()));
 +
 +        DeassociationPatch deassociationPatch = new DeassociationPatch();
 +        deassociationPatch.setKey(actual.getKey());
 +        deassociationPatch.setAction(ResourceDeassociationAction.UNLINK);
 +        deassociationPatch.getResources().add(RESOURCE_NAME_CSV);
 +
 +        assertNotNull(userService.deassociate(deassociationPatch).readEntity(BulkActionResult.class));
 +
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertTrue(actual.getResources().isEmpty());
 +
 +        assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()));
 +    }
 +
 +    @Test
 +    public void link() {
 +        UserTO userTO = getUniqueSampleTO("link@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getVirAttrs().clear();
 +        userTO.getAuxClasses().add("csv");
 +        userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +        assertTrue(actual.getResources().isEmpty());
 +
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +            fail();
 +        } catch (Exception e) {
 +            assertNotNull(e);
 +        }
 +
 +        AssociationPatch associationPatch = new AssociationPatch();
 +        associationPatch.setKey(actual.getKey());
 +        associationPatch.setAction(ResourceAssociationAction.LINK);
 +        associationPatch.getResources().add(RESOURCE_NAME_CSV);
 +
 +        assertNotNull(userService.associate(associationPatch).readEntity(BulkActionResult.class));
 +
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertFalse(actual.getResources().isEmpty());
 +
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +            fail();
 +        } catch (Exception e) {
 +            assertNotNull(e);
 +        }
 +    }
 +
 +    @Test
 +    public void unassign() {
 +        UserTO userTO = getUniqueSampleTO("unassign@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getVirAttrs().clear();
 +        userTO.getAuxClasses().add("csv");
 +        userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +        userTO.getResources().add(RESOURCE_NAME_CSV);
 +
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +        assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()));
 +
 +        DeassociationPatch deassociationPatch = new DeassociationPatch();
 +        deassociationPatch.setKey(actual.getKey());
 +        deassociationPatch.setAction(ResourceDeassociationAction.UNASSIGN);
 +        deassociationPatch.getResources().add(RESOURCE_NAME_CSV);
 +
 +        assertNotNull(userService.deassociate(deassociationPatch).readEntity(BulkActionResult.class));
 +
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertTrue(actual.getResources().isEmpty());
 +
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +            fail();
 +        } catch (Exception e) {
 +            assertNotNull(e);
 +        }
 +    }
 +
 +    @Test
 +    public void assign() {
 +        UserTO userTO = getUniqueSampleTO("assign@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getVirAttrs().clear();
 +        userTO.getAuxClasses().add("csv");
 +        userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +        assertTrue(actual.getResources().isEmpty());
 +
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +            fail();
 +        } catch (Exception e) {
 +            assertNotNull(e);
 +        }
 +
 +        AssociationPatch associationPatch = new AssociationPatch();
 +        associationPatch.setKey(actual.getKey());
 +        associationPatch.setValue("password");
 +        associationPatch.setAction(ResourceAssociationAction.ASSIGN);
 +        associationPatch.getResources().add(RESOURCE_NAME_CSV);
 +
 +        assertNotNull(userService.associate(associationPatch).readEntity(BulkActionResult.class));
 +
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertFalse(actual.getResources().isEmpty());
 +        assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()));
 +    }
 +
 +    @Test
 +    public void deprovision() {
 +        UserTO userTO = getUniqueSampleTO("deprovision@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getVirAttrs().clear();
 +        userTO.getAuxClasses().add("csv");
 +        userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +        userTO.getResources().add(RESOURCE_NAME_CSV);
 +
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +        assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()));
 +
 +        DeassociationPatch deassociationPatch = new DeassociationPatch();
 +        deassociationPatch.setKey(actual.getKey());
 +        deassociationPatch.setAction(ResourceDeassociationAction.DEPROVISION);
 +        deassociationPatch.getResources().add(RESOURCE_NAME_CSV);
 +
 +        assertNotNull(userService.deassociate(deassociationPatch).readEntity(BulkActionResult.class));
 +
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertFalse(actual.getResources().isEmpty());
 +
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.NotFound, e.getType());
 +        }
 +    }
 +
 +    @Test
 +    public void provision() {
 +        UserTO userTO = getUniqueSampleTO("provision@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getVirAttrs().clear();
 +        userTO.getAuxClasses().add("csv");
 +        userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +        assertTrue(actual.getResources().isEmpty());
 +
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +            fail();
 +        } catch (Exception e) {
 +            assertNotNull(e);
 +        }
 +
 +        AssociationPatch associationPatch = new AssociationPatch();
 +        associationPatch.setKey(actual.getKey());
 +        associationPatch.setValue("password");
 +        associationPatch.setAction(ResourceAssociationAction.PROVISION);
 +        associationPatch.getResources().add(RESOURCE_NAME_CSV);
 +
 +        assertNotNull(userService.associate(associationPatch).readEntity(BulkActionResult.class));
 +
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertTrue(actual.getResources().isEmpty());
 +        assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()));
 +    }
 +
 +    @Test
 +    public void deprovisionUnlinked() {
 +        UserTO userTO = getUniqueSampleTO("provision@syncope.apache.org");
 +        userTO.getResources().clear();
 +        userTO.getMemberships().clear();
 +        userTO.getDerAttrs().clear();
 +        userTO.getVirAttrs().clear();
 +        userTO.getAuxClasses().add("csv");
 +        userTO.getDerAttrs().add(attrTO("csvuserid", null));
 +
 +        UserTO actual = createUser(userTO);
 +        assertNotNull(actual);
 +        assertTrue(actual.getResources().isEmpty());
 +
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +            fail();
 +        } catch (Exception e) {
 +            assertNotNull(e);
 +        }
 +
 +        AssociationPatch associationPatch = new AssociationPatch();
 +        associationPatch.setKey(actual.getKey());
 +        associationPatch.setValue("password");
 +        associationPatch.setAction(ResourceAssociationAction.PROVISION);
 +        associationPatch.getResources().add(RESOURCE_NAME_CSV);
 +
 +        assertNotNull(userService.associate(associationPatch).readEntity(BulkActionResult.class));
 +
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertTrue(actual.getResources().isEmpty());
 +        assertNotNull(resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey()));
 +
 +        DeassociationPatch deassociationPatch = new DeassociationPatch();
 +        deassociationPatch.setKey(actual.getKey());
 +        deassociationPatch.setAction(ResourceDeassociationAction.DEPROVISION);
 +        deassociationPatch.getResources().add(RESOURCE_NAME_CSV);
 +
 +        assertNotNull(userService.deassociate(deassociationPatch).readEntity(BulkActionResult.class));
 +
 +        actual = userService.read(actual.getKey());
 +        assertNotNull(actual);
 +        assertTrue(actual.getResources().isEmpty());
 +
 +        try {
 +            resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), actual.getKey());
 +            fail();
 +        } catch (Exception e) {
 +            assertNotNull(e);
 +        }
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE420() {
 +        RealmTO realm = realmService.list("/even/two").iterator().next();
 +        assertNotNull(realm);
 +        realm.getActionsClassNames().add(DoubleValueLogicActions.class.getName());
 +        realmService.update(realm);
 +
 +        UserTO userTO = getUniqueSampleTO("syncope420@syncope.apache.org");
 +        userTO.setRealm(realm.getFullPath());
 +        userTO.getPlainAttrs().add(attrTO("makeItDouble", "3"));
 +
 +        userTO = createUser(userTO);
 +        assertEquals("6", userTO.getPlainAttrMap().get("makeItDouble").getValues().get(0));
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(userTO.getKey());
 +        userPatch.getPlainAttrs().add(attrAddReplacePatch("makeItDouble", "7"));
 +
 +        userTO = updateUser(userPatch);
 +        assertEquals("14", userTO.getPlainAttrMap().get("makeItDouble").getValues().get(0));
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE426() {
 +        UserTO userTO = getUniqueSampleTO("syncope426@syncope.apache.org");
 +        userTO = createUser(userTO);
 +        assertNotNull(userTO);
 +
 +        UserPatch userPatch = new UserPatch();
 +   

<TRUNCATED>

[38/54] [abbrv] syncope git commit: refactoring of the schema and notification stack + bugfixing, SYNCOPE-158

Posted by fm...@apache.org.
refactoring of the schema and notification stack + bugfixing, SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 80f2548a004db0970fbfbd0773a068a8f9c9a836
Parents: 171c0ae
Author: massi <ma...@tirasa.net>
Authored: Thu Oct 22 11:12:50 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Thu Oct 22 11:12:50 2015 +0200

----------------------------------------------------------------------
 .../cli/commands/CommonsResultManager.java      |  10 +-
 .../client/cli/commands/HelpCommand.java        | 113 -------
 .../client/cli/commands/InfoCommand.java        | 339 -------------------
 .../cli/commands/NotificationCommand.java       | 169 ---------
 .../client/cli/commands/SchemaCommand.java      | 309 -----------------
 .../AbstractConfigurationCommand.java           |   2 +-
 .../commands/domain/AbstractDomainCommand.java  |   2 +-
 .../syncope/client/cli/commands/help/Help.java  |  43 +++
 .../client/cli/commands/help/HelpCommand.java   |  90 +++++
 .../cli/commands/help/HelpResultManager.java    |  25 ++
 .../syncope/client/cli/commands/info/Info.java  | 243 +++++++++++++
 .../client/cli/commands/info/InfoCommand.java   | 180 ++++++++++
 .../cli/commands/info/InfoResultManager.java    |  25 ++
 .../commands/logger/AbstractLoggerCommand.java  |   2 +-
 .../cli/commands/logger/LoggerCreate.java       |   4 +-
 .../cli/commands/logger/LoggerUpdate.java       |   6 +-
 .../cli/commands/logger/LoggerUpdateAll.java    |   6 +-
 .../AbstractNotificationCommand.java            |  30 ++
 .../notification/NotificationCommand.java       | 109 ++++++
 .../notification/NotificationDelete.java        |  56 +++
 .../commands/notification/NotificationList.java |  35 ++
 .../commands/notification/NotificationRead.java |  54 +++
 .../notification/NotificationResultManager.java |  25 ++
 .../commands/schema/AbstractSchemaCommand.java  |  30 ++
 .../cli/commands/schema/SchemaCommand.java      | 127 +++++++
 .../cli/commands/schema/SchemaDelete.java       |  64 ++++
 .../client/cli/commands/schema/SchemaList.java  |  70 ++++
 .../cli/commands/schema/SchemaListAll.java      |  55 +++
 .../cli/commands/schema/SchemaListDerived.java  |  40 +++
 .../cli/commands/schema/SchemaListPlain.java    |  40 +++
 .../cli/commands/schema/SchemaListVirtual.java  |  40 +++
 .../client/cli/commands/schema/SchemaRead.java  |  78 +++++
 .../commands/schema/SchemaResultManager.java    |  96 ++++++
 .../syncope/client/cli/messages/Table.java      |  12 +-
 34 files changed, 1585 insertions(+), 944 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
index 255b99b..c316e13 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/CommonsResultManager.java
@@ -19,8 +19,6 @@
 package org.apache.syncope.client.cli.commands;
 
 import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.util.CommandUtils;
-import org.apache.syncope.common.lib.types.LoggerLevel;
 
 public abstract class CommonsResultManager {
 
@@ -32,8 +30,12 @@ public abstract class CommonsResultManager {
         Messages.printNofFoundMessage(what, parameter);
     }
 
-    public void typeNotValidError(final String parameter) {
-        Messages.printTypeNotValidMessage("logger level", parameter, CommandUtils.fromEnumToArray(LoggerLevel.class));
+    public void notBooleanDeletedError(final String what, final String key) {
+        Messages.printNotBooleanDeletedMessage(what, key);
+    }
+
+    public void typeNotValidError(final String what, final String parameter, final String[] options) {
+        Messages.printTypeNotValidMessage(what, parameter, options);
     }
 
     public void commandOptionError(final String message) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
deleted file mode 100644
index d167de4..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.cli.commands;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.cli.Command;
-import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.util.CommandUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Command(name = "help")
-public class HelpCommand extends AbstractCommand {
-
-    private static final Logger LOG = LoggerFactory.getLogger(HelpCommand.class);
-
-    @Override
-    public void execute(final Input input) {
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
-        if (StringUtils.isBlank(input.getOption())) {
-            input.setOption(Options.HELP.getOptionName());
-        }
-
-        switch (Options.fromName(input.getOption())) {
-            case HELP:
-                final StringBuilder generalHelpBuilder = new StringBuilder("General help\n");
-                try {
-                    for (final AbstractCommand command : CommandUtils.commands()) {
-                        generalHelpBuilder.append("Command: ")
-                                .append(command.getClass().getAnnotation(Command.class).name())
-                                .append("\n")
-                                .append(command.getHelpMessage())
-                                .append("\n")
-                                .append(" \n");
-                    }
-                    System.out.println(generalHelpBuilder.toString());
-                } catch (final IllegalAccessException | IllegalArgumentException | InstantiationException e) {
-                    Messages.printMessage(e.getMessage());
-                }
-                break;
-            default:
-                Messages.printDefaultMessage(input.getOption(), CommandUtils.helpMessage("info", Options.toList()));
-                break;
-        }
-    }
-
-    @Override
-    public String getHelpMessage() {
-        return CommandUtils.helpMessage("help", Options.toList());
-    }
-
-    private enum Options {
-
-        HELP("--print");
-
-        private final String optionName;
-
-        Options(final String optionName) {
-            this.optionName = optionName;
-        }
-
-        public String getOptionName() {
-            return optionName;
-        }
-
-        public boolean equalsOptionName(final String otherName) {
-            return (otherName == null) ? false : optionName.equals(otherName);
-        }
-
-        public static Options fromName(final String name) {
-            Options optionToReturn = HELP;
-            for (final Options option : Options.values()) {
-                if (option.equalsOptionName(name)) {
-                    optionToReturn = option;
-                }
-            }
-            return optionToReturn;
-        }
-
-        public static List<String> toList() {
-            final List<String> options = new ArrayList<>();
-            for (final Options value : values()) {
-                options.add(value.getOptionName());
-            }
-            return options;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
deleted file mode 100644
index 8868f9b..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * 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.cli.commands;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.cli.Command;
-import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.SyncopeServices;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.util.CommandUtils;
-import org.apache.syncope.common.lib.to.SyncopeTO;
-import org.apache.syncope.common.rest.api.service.SyncopeService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Command(name = "info")
-public class InfoCommand extends AbstractCommand {
-
-    private static final Logger LOG = LoggerFactory.getLogger(InfoCommand.class);
-
-    @Override
-    public void execute(final Input input) {
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
-        if (StringUtils.isBlank(input.getOption())) {
-            input.setOption(Options.HELP.getOptionName());
-        }
-
-        final SyncopeService syncopeService = SyncopeServices.get(SyncopeService.class);
-        final SyncopeTO syncopeTO = syncopeService.info();
-        switch (Options.fromName(input.getOption())) {
-            case VERSION:
-                try {
-                    Messages.printMessage("Syncope version: " + syncopeTO.getVersion());
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case PWD_RESET_ALLOWED:
-                try {
-                    Messages.printMessage("Password reset allowed: " + syncopeTO.isPwdResetAllowed());
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case PWD_RESET_WITH_SECURITY_QUESTION:
-                try {
-                    Messages.printMessage("Password reset requiring security question: "
-                            + syncopeTO.isPwdResetRequiringSecurityQuestions());
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case SELF_REG_ALLOWED:
-                try {
-                    Messages.printMessage("Self registration allowed: " + syncopeTO.isSelfRegAllowed());
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case PROVISIONING_MANAGER:
-                try {
-                    Messages.printMessage(
-                            "Any object provisioning manager class: " + syncopeTO.getAnyObjectProvisioningManager(),
-                            "User       provisioning manager class: " + syncopeTO.getUserProvisioningManager(),
-                            "Group      provisioning manager class: " + syncopeTO.getGroupProvisioningManager());
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case WORKFLOW_ADAPTER:
-                try {
-                    Messages.printMessage(
-                            "Any object workflow adapter class: " + syncopeTO.getAnyObjectWorkflowAdapter(),
-                            "User       workflow adapter class: " + syncopeTO.getUserWorkflowAdapter(),
-                            "Group      workflow adapter class: " + syncopeTO.getGroupWorkflowAdapter());
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case ACCOUNT_RULES:
-                try {
-                    for (final String accountRule : syncopeTO.getAccountRules()) {
-                        Messages.printMessage("Account rule: " + accountRule);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case CONNID_LOCATION:
-                try {
-                    for (final String location : syncopeTO.getConnIdLocations()) {
-                        Messages.printMessage("ConnId location: " + location);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case LOGIC_ACTIONS:
-                try {
-                    for (final String logic : syncopeTO.getLogicActions()) {
-                        Messages.printMessage("Logic action: " + logic);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case MAIL_TEMPLATES:
-                try {
-                    for (final String template : syncopeTO.getMailTemplates()) {
-                        Messages.printMessage("Mail template: " + template);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case MAPPING_ITEM_TRANSFORMERS:
-                try {
-                    for (final String tranformer : syncopeTO.getMappingItemTransformers()) {
-                        Messages.printMessage("Mapping item tranformer: " + tranformer);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case PASSWORD_RULES:
-                try {
-                    for (final String rules : syncopeTO.getPasswordRules()) {
-                        Messages.printMessage("Password rule: " + rules);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case PROPAGATION_ACTIONS:
-                try {
-                    for (final String action : syncopeTO.getPropagationActions()) {
-                        Messages.printMessage("Propagation action: " + action);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case PUSH_ACTIONS:
-                try {
-                    for (final String action : syncopeTO.getPushActions()) {
-                        Messages.printMessage("Push action: " + action);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case PUSH_CORRELATION_ACTIONS:
-                try {
-                    for (final String rule : syncopeTO.getPushCorrelationRules()) {
-                        Messages.printMessage("Push correlation rule: " + rule);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case REPORTLETS:
-                try {
-                    for (final String reportlet : syncopeTO.getReportlets()) {
-                        Messages.printMessage("Reportlet: " + reportlet);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case SYNC_ACTIONS:
-                try {
-                    for (final String action : syncopeTO.getSyncActions()) {
-                        Messages.printMessage("Sync action: " + action);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case SYNC_CORRELATION_RULES:
-                try {
-                    for (final String rule : syncopeTO.getSyncCorrelationRules()) {
-                        Messages.printMessage("Sync correlation rule: " + rule);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case TASK_JOBS:
-                try {
-                    for (final String job : syncopeTO.getTaskJobs()) {
-                        Messages.printMessage("Task job: " + job);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case VALIDATORS:
-                try {
-                    for (final String validator : syncopeTO.getValidators()) {
-                        Messages.printMessage("Validator: " + validator);
-                    }
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case PASSWORD_GENERATOR:
-                try {
-                    Messages.printMessage(
-                            "Password generator class: " + syncopeTO.getPasswordGenerator());
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case VIR_ATTR_CACHE:
-                try {
-                    Messages.printMessage(
-                            "Virtual attribute cache class: " + syncopeTO.getVirAttrCache());
-                } catch (final Exception ex) {
-                    Messages.printMessage(ex.getMessage());
-                    break;
-                }
-                break;
-            case HELP:
-                System.out.println(CommandUtils.helpMessage("info", Options.toList()));
-                break;
-            default:
-                Messages.printDefaultMessage(input.getOption(), CommandUtils.helpMessage("info", Options.toList()));
-                break;
-        }
-    }
-
-    @Override
-    public String getHelpMessage() {
-        return CommandUtils.helpMessage("info", Options.toList());
-    }
-
-    private enum Options {
-
-        VERSION("--version"),
-        PWD_RESET_ALLOWED("--pwd-reset-allowed"),
-        PWD_RESET_WITH_SECURITY_QUESTION("--pwd-reset-with-question"),
-        SELF_REG_ALLOWED("--self-reg-allowed"),
-        PROVISIONING_MANAGER("--provisioning-manager-classes"),
-        WORKFLOW_ADAPTER("--workflow-adapter-classes"),
-        ACCOUNT_RULES("--account-rules-classes"),
-        CONNID_LOCATION("--connid-locations"),
-        LOGIC_ACTIONS("--logic-actions"),
-        MAIL_TEMPLATES("--mail-templates"),
-        MAPPING_ITEM_TRANSFORMERS("--mapping-item-transformers"),
-        PASSWORD_RULES("--password-rules"),
-        PROPAGATION_ACTIONS("--propagation-actions"),
-        PUSH_ACTIONS("--push-actions"),
-        PUSH_CORRELATION_ACTIONS("--push-correlation-actions"),
-        REPORTLETS("--reportlets"),
-        SYNC_ACTIONS("--sync-actions"),
-        SYNC_CORRELATION_RULES("--sync-correlation-rules"),
-        TASK_JOBS("--task-jobs"),
-        VALIDATORS("--validators"),
-        PASSWORD_GENERATOR("--password-generator"),
-        VIR_ATTR_CACHE("--vir-attr-cache"),
-        HELP("--help");
-
-        private final String optionName;
-
-        Options(final String optionName) {
-            this.optionName = optionName;
-        }
-
-        public String getOptionName() {
-            return optionName;
-        }
-
-        public boolean equalsOptionName(final String otherName) {
-            return (otherName == null) ? false : optionName.equals(otherName);
-        }
-
-        public static Options fromName(final String name) {
-            Options optionToReturn = HELP;
-            for (final Options option : Options.values()) {
-                if (option.equalsOptionName(name)) {
-                    optionToReturn = option;
-                }
-            }
-            return optionToReturn;
-        }
-
-        public static List<String> toList() {
-            final List<String> options = new ArrayList<>();
-            for (final Options value : values()) {
-                options.add(value.getOptionName());
-            }
-            return options;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
deleted file mode 100644
index 3d1866b..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * 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.cli.commands;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.ws.WebServiceException;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.cli.Command;
-import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.SyncopeServices;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.NotificationTO;
-import org.apache.syncope.common.rest.api.service.NotificationService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Command(name = "notification")
-public class NotificationCommand extends AbstractCommand {
-
-    private static final Logger LOG = LoggerFactory.getLogger(NotificationCommand.class);
-
-    private static final String HELP_MESSAGE = "Usage: notification [options]\n"
-            + "  Options:\n"
-            + "    --help \n"
-            + "    --list \n"
-            + "    --read \n"
-            + "       Syntax: --read {NOTIFICATION-ID} \n"
-            + "    --delete \n"
-            + "       Syntax: --delete {NOTIFICATION-ID}";
-    
-    @Override
-    public void execute(final Input input) {
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
-        final String[] parameters = input.getParameters();
-
-        if (StringUtils.isBlank(input.getOption())) {
-            input.setOption(Options.HELP.getOptionName());
-        }
-
-        final NotificationService notificationService = SyncopeServices.get(NotificationService.class);
-        switch (Options.fromName(input.getOption())) {
-            case LIST:
-                try {
-                    for (final NotificationTO notificationTO : notificationService.list()) {
-                        System.out.println(notificationTO);
-                    }
-                } catch (final SyncopeClientException ex) {
-                    Messages.printMessage(ex.getMessage());
-                }
-                break;
-            case READ:
-                final String readErrorMessage = "notification --read {NOTIFICATION-ID} {NOTIFICATION-ID} [...]";
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            System.out.println(notificationService.read(Long.valueOf(parameter)));
-                        } catch (final NumberFormatException ex) {
-                            Messages.printIdNotNumberDeletedMessage("notification", parameter);
-                        } catch (final WebServiceException | SyncopeClientException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Notification", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(readErrorMessage);
-                }
-                break;
-            case DELETE:
-                final String deleteErrorMessage = "notification --delete {NOTIFICATION-ID} {NOTIFICATION-ID} [...]";
-
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            notificationService.delete(Long.valueOf(parameter));
-                            Messages.printDeletedMessage("Notification", parameter);
-                        } catch (final WebServiceException | SyncopeClientException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Notification", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                        } catch (final NumberFormatException ex) {
-                            Messages.printIdNotNumberDeletedMessage("notification", parameter);
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(deleteErrorMessage);
-                }
-                break;
-            case HELP:
-                System.out.println(HELP_MESSAGE);
-                break;
-            default:
-                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
-        }
-    }
-
-    @Override
-    public String getHelpMessage() {
-        return HELP_MESSAGE;
-    }
-
-    private enum Options {
-
-        HELP("--help"),
-        LIST("--list"),
-        READ("--read"),
-        DELETE("--delete");
-
-        private final String optionName;
-
-        Options(final String optionName) {
-            this.optionName = optionName;
-        }
-
-        public String getOptionName() {
-            return optionName;
-        }
-
-        public boolean equalsOptionName(final String otherName) {
-            return (otherName == null) ? false : optionName.equals(otherName);
-        }
-
-        public static Options fromName(final String name) {
-            Options optionToReturn = HELP;
-            for (final Options option : Options.values()) {
-                if (option.equalsOptionName(name)) {
-                    optionToReturn = option;
-                }
-            }
-            return optionToReturn;
-        }
-
-        public static List<String> toList() {
-            final List<String> options = new ArrayList<>();
-            for (final Options value : values()) {
-                options.add(value.getOptionName());
-            }
-            return options;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
deleted file mode 100644
index e00ae3f..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * 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.cli.commands;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import javax.xml.ws.WebServiceException;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.cli.Command;
-import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.SyncopeServices;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.util.CommandUtils;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.AbstractSchemaTO;
-import org.apache.syncope.common.lib.to.DerSchemaTO;
-import org.apache.syncope.common.lib.to.PlainSchemaTO;
-import org.apache.syncope.common.lib.to.VirSchemaTO;
-import org.apache.syncope.common.lib.types.SchemaType;
-import org.apache.syncope.common.rest.api.service.SchemaService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Command(name = "schema")
-public class SchemaCommand extends AbstractCommand {
-
-    private static final Logger LOG = LoggerFactory.getLogger(SchemaCommand.class);
-
-    private static final String HELP_MESSAGE = "Usage: schema [options]\n"
-            + "  Options:\n"
-            + "    --help \n"
-            + "    --list-all\n"
-            + "    --list-plain\n"
-            + "    --list-derived\n"
-            + "    --list-virtual\n"
-            + "    --read {SCHEMA-TYPE} {SCHEMA-KEY}\n"
-            + "        Schema type: PLAIN / DERIVED / VIRTUAL\n"
-            + "    --delete {SCHEMA-TYPE} {SCHEMA-KEY}\n"
-            + "        Schema type: PLAIN / DERIVED / VIRTUAL";
-
-    @Override
-    public void execute(final Input input) {
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
-        String[] parameters = input.getParameters();
-
-        if (StringUtils.isBlank(input.getOption())) {
-            input.setOption(Options.HELP.getOptionName());
-        }
-
-        final SchemaService schemaService = SyncopeServices.get(SchemaService.class);
-        switch (Options.fromName(input.getOption())) {
-            case LIST:
-                final String listErrorMessage = "schema --list {SCHEMA-TYPE}\n"
-                        + "   Schema type: PLAIN / DERIVED / VIRTUAL";
-                if (parameters.length == 1) {
-                    try {
-                        final SchemaType schemaType = SchemaType.valueOf(input.firstParameter());
-                        System.out.println("");
-                        for (final AbstractSchemaTO schemaTO : schemaService.list(schemaType)) {
-                            switch (schemaType) {
-                                case PLAIN:
-                                    System.out.println(" - Schema key: " + ((PlainSchemaTO) schemaTO).getKey());
-                                    System.out.println("      type: " + ((PlainSchemaTO) schemaTO).getType());
-                                    System.out.println("      is mandatory: "
-                                            + ((PlainSchemaTO) schemaTO).getMandatoryCondition());
-                                    break;
-                                case DERIVED:
-                                    System.out.println(" - Schema key: " + ((DerSchemaTO) schemaTO).getKey());
-                                    System.out.println("      expression: " + ((DerSchemaTO) schemaTO).getExpression());
-                                    break;
-                                case VIRTUAL:
-                                    System.out.println(" - Schema key: " + ((VirSchemaTO) schemaTO).getKey());
-                                    break;
-                                default:
-                                    break;
-                            }
-                        }
-                        System.out.println("");
-                    } catch (final SyncopeClientException ex) {
-                        Messages.printMessage(ex.getMessage());
-                    } catch (final IllegalArgumentException ex) {
-                        Messages.printTypeNotValidMessage(
-                                "schema", input.firstParameter(), CommandUtils.fromEnumToArray(SchemaType.class));
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(listErrorMessage);
-                }
-                break;
-            case LIST_ALL:
-                try {
-                    for (final SchemaType value : SchemaType.values()) {
-                        System.out.println("");
-                        System.out.println(value + " schemas");
-                        for (final AbstractSchemaTO schemaTO : schemaService.list(value)) {
-                            System.out.println("   - Name: " + schemaTO.getKey() + " type: "
-                                    + schemaTO.getAnyTypeClass());
-                        }
-                        System.out.println("");
-                    }
-                } catch (final SyncopeClientException | WebServiceException ex) {
-                    Messages.printMessage(ex.getMessage());
-                }
-                break;
-            case LIST_PLAIN:
-                try {
-                    System.out.println("");
-                    for (final AbstractSchemaTO schemaTO : schemaService.list(SchemaType.PLAIN)) {
-                        System.out.println(" - Schema key: " + ((PlainSchemaTO) schemaTO).getKey());
-                        System.out.println("      type: " + ((PlainSchemaTO) schemaTO).getType());
-                        System.out.println("      is mandatory: "
-                                + ((PlainSchemaTO) schemaTO).getMandatoryCondition());
-                    }
-                    System.out.println("");
-                } catch (final SyncopeClientException | WebServiceException ex) {
-                    Messages.printMessage(ex.getMessage());
-                }
-                break;
-            case LIST_DERIVED:
-                try {
-                    System.out.println("");
-                    for (final AbstractSchemaTO schemaTO : schemaService.list(SchemaType.DERIVED)) {
-                        System.out.println(" - Schema key: " + ((DerSchemaTO) schemaTO).getKey());
-                        System.out.println("      expression: " + ((DerSchemaTO) schemaTO).getExpression());
-                    }
-                    System.out.println("");
-                } catch (final SyncopeClientException | WebServiceException ex) {
-                    Messages.printMessage(ex.getMessage());
-                }
-                break;
-            case LIST_VIRTUAL:
-                try {
-                    System.out.println("");
-                    for (final AbstractSchemaTO schemaTO : schemaService.list(SchemaType.VIRTUAL)) {
-                        System.out.println(" - Schema key: " + ((VirSchemaTO) schemaTO).getKey());
-                    }
-                    System.out.println("");
-                } catch (final SyncopeClientException | WebServiceException ex) {
-                    Messages.printMessage(ex.getMessage());
-                }
-                break;
-            case READ:
-                final String readErrorMessage = "schema --read {SCHEMA-TYPE} {SCHEMA-KEY}\n"
-                        + "   Schema type: PLAIN / DERIVED / VIRTUAL";
-                if (parameters.length >= 2) {
-                    parameters = Arrays.copyOfRange(parameters, 1, parameters.length);
-                    try {
-                        final SchemaType schemaType = SchemaType.valueOf(input.firstParameter());
-                        System.out.println("");
-                        for (final String parameter : parameters) {
-                            final AbstractSchemaTO schemaTO = schemaService.read(schemaType, parameter);
-                            switch (schemaType) {
-                                case PLAIN:
-                                    System.out.println(" - Schema key: " + ((PlainSchemaTO) schemaTO).getKey());
-                                    System.out.println("      any type class: "
-                                            + ((PlainSchemaTO) schemaTO).getAnyTypeClass());
-                                    System.out.println("      conversion pattern: "
-                                            + ((PlainSchemaTO) schemaTO).getConversionPattern());
-                                    System.out.println("      enumeration keys: "
-                                            + ((PlainSchemaTO) schemaTO).getEnumerationKeys());
-                                    System.out.println("      enumeration values: "
-                                            + ((PlainSchemaTO) schemaTO).getEnumerationValues());
-                                    System.out.println("      mandatory condition: "
-                                            + ((PlainSchemaTO) schemaTO).getMandatoryCondition());
-                                    System.out.println("      mime type: " + ((PlainSchemaTO) schemaTO).getMimeType());
-                                    System.out.println("      secret key: "
-                                            + ((PlainSchemaTO) schemaTO).getSecretKey());
-                                    System.out.println("      validator class: "
-                                            + ((PlainSchemaTO) schemaTO).getValidatorClass());
-                                    System.out.println("      cipher algorithm: "
-                                            + ((PlainSchemaTO) schemaTO).getCipherAlgorithm());
-                                    System.out.println("      TYPE: "
-                                            + ((PlainSchemaTO) schemaTO).getType());
-                                    break;
-                                case DERIVED:
-                                    System.out.println(" - Schema key: " + ((DerSchemaTO) schemaTO).getKey());
-                                    System.out.println("      any type class: "
-                                            + ((DerSchemaTO) schemaTO).getAnyTypeClass());
-                                    System.out.println("      expression: " + ((DerSchemaTO) schemaTO).getExpression());
-                                    break;
-                                case VIRTUAL:
-                                    System.out.println(" - Schema key: " + ((VirSchemaTO) schemaTO).getKey());
-                                    System.out.println("      any type class: "
-                                            + ((VirSchemaTO) schemaTO).getAnyTypeClass());
-                                    break;
-                                default:
-                                    break;
-                            }
-                            System.out.println("");
-                        }
-                    } catch (final SyncopeClientException | WebServiceException ex) {
-                        if (ex.getMessage().startsWith("NotFound")) {
-                            Messages.printNofFoundMessage("Schema", parameters[0]);
-                        } else {
-                            Messages.printMessage(ex.getMessage());
-                        }
-                    } catch (final IllegalArgumentException ex) {
-                        Messages.printTypeNotValidMessage(
-                                "schema", input.firstParameter(), CommandUtils.fromEnumToArray(SchemaType.class));
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(readErrorMessage);
-                }
-                break;
-            case DELETE:
-                final String deleteErrorMessage = "schema --delete {SCHEMA-TYPE} {SCHEMA-KEY}\n"
-                        + "   Schema type: PLAIN / DERIVED / VIRTUAL";
-                if (parameters.length >= 2) {
-                    parameters = Arrays.copyOfRange(parameters, 1, parameters.length);
-                    try {
-                        for (final String parameter : parameters) {
-                            schemaService.delete(SchemaType.valueOf(input.firstParameter()), parameter);
-                            Messages.printDeletedMessage("Schema", parameter);
-                        }
-                    } catch (final SyncopeClientException | WebServiceException ex) {
-                        if (ex.getMessage().startsWith("NotFound")) {
-                            Messages.printNofFoundMessage("Schema", parameters[0]);
-                        } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
-                            Messages.printMessage(
-                                    "You cannot delete schema " + parameters[0]);
-                        } else {
-                            Messages.printMessage(ex.getMessage());
-                        }
-                    } catch (final IllegalArgumentException ex) {
-                        Messages.printTypeNotValidMessage(
-                                "schema", input.firstParameter(), CommandUtils.fromEnumToArray(SchemaType.class));
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(deleteErrorMessage);
-                }
-                break;
-            case HELP:
-                System.out.println(HELP_MESSAGE);
-                break;
-            default:
-                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
-        }
-    }
-
-    @Override
-    public String getHelpMessage() {
-        return HELP_MESSAGE;
-    }
-
-    private enum Options {
-
-        HELP("--help"),
-        LIST("--list"),
-        LIST_ALL("--list-all"),
-        LIST_PLAIN("--list-plain"),
-        LIST_DERIVED("--list-derived"),
-        LIST_VIRTUAL("--list-virtual"),
-        READ("--read"),
-        DELETE("--delete");
-
-        private final String optionName;
-
-        Options(final String optionName) {
-            this.optionName = optionName;
-        }
-
-        public String getOptionName() {
-            return optionName;
-        }
-
-        public boolean equalsOptionName(final String otherName) {
-            return (otherName == null) ? false : optionName.equals(otherName);
-        }
-
-        public static Options fromName(final String name) {
-            Options optionToReturn = HELP;
-            for (final Options option : Options.values()) {
-                if (option.equalsOptionName(name)) {
-                    optionToReturn = option;
-                }
-            }
-            return optionToReturn;
-        }
-
-        public static List<String> toList() {
-            final List<String> options = new ArrayList<>();
-            for (final Options value : values()) {
-                options.add(value.getOptionName());
-            }
-            return options;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/AbstractConfigurationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/AbstractConfigurationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/AbstractConfigurationCommand.java
index 59fc423..2942c07 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/AbstractConfigurationCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/AbstractConfigurationCommand.java
@@ -21,7 +21,7 @@ package org.apache.syncope.client.cli.commands.configuration;
 import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.common.rest.api.service.ConfigurationService;
 
-public class AbstractConfigurationCommand {
+public abstract class AbstractConfigurationCommand {
 
     protected final ConfigurationService configurationService = SyncopeServices.get(ConfigurationService.class);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/AbstractDomainCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/AbstractDomainCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/AbstractDomainCommand.java
index 8650ef7..b5bfca5 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/AbstractDomainCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/domain/AbstractDomainCommand.java
@@ -21,7 +21,7 @@ package org.apache.syncope.client.cli.commands.domain;
 import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.common.rest.api.service.DomainService;
 
-public class AbstractDomainCommand {
+public abstract class AbstractDomainCommand {
 
     protected final DomainService domainService = SyncopeServices.get(DomainService.class);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/Help.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/Help.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/Help.java
new file mode 100644
index 0000000..c658beb
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/Help.java
@@ -0,0 +1,43 @@
+/*
+ * 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.cli.commands.help;
+
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.commands.AbstractCommand;
+import org.apache.syncope.client.cli.util.CommandUtils;
+
+public class Help {
+
+    public void help() {
+        final StringBuilder generalHelpBuilder = new StringBuilder("General help\n");
+        try {
+            for (final AbstractCommand command : CommandUtils.commands()) {
+                generalHelpBuilder.append("Command: ")
+                        .append(command.getClass().getAnnotation(Command.class).name())
+                        .append("\n")
+                        .append(command.getHelpMessage())
+                        .append("\n")
+                        .append(" \n");
+            }
+            System.out.println(generalHelpBuilder.toString());
+        } catch (final IllegalAccessException | IllegalArgumentException | InstantiationException e) {
+            new HelpResultManager().generic(e.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/HelpCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/HelpCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/HelpCommand.java
new file mode 100644
index 0000000..eed0924
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/HelpCommand.java
@@ -0,0 +1,90 @@
+/*
+ * 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.cli.commands.help;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.commands.AbstractCommand;
+import org.apache.syncope.client.cli.util.CommandUtils;
+
+@Command(name = "help")
+public class HelpCommand extends AbstractCommand {
+
+    @Override
+    public void execute(final Input input) {
+        if (StringUtils.isBlank(input.getOption())) {
+            input.setOption(Options.HELP.getOptionName());
+        }
+
+        switch (Options.fromName(input.getOption())) {
+            case HELP:
+                new Help().help();
+                break;
+            default:
+                new HelpResultManager().defaultError(
+                        input.getOption(), CommandUtils.helpMessage("info", Options.toList()));
+                break;
+        }
+    }
+
+    @Override
+    public String getHelpMessage() {
+        return CommandUtils.helpMessage("help", Options.toList());
+    }
+
+    private enum Options {
+
+        HELP("--print");
+
+        private final String optionName;
+
+        Options(final String optionName) {
+            this.optionName = optionName;
+        }
+
+        public String getOptionName() {
+            return optionName;
+        }
+
+        public boolean equalsOptionName(final String otherName) {
+            return (otherName == null) ? false : optionName.equals(otherName);
+        }
+
+        public static Options fromName(final String name) {
+            Options optionToReturn = HELP;
+            for (final Options option : Options.values()) {
+                if (option.equalsOptionName(name)) {
+                    optionToReturn = option;
+                }
+            }
+            return optionToReturn;
+        }
+
+        public static List<String> toList() {
+            final List<String> options = new ArrayList<>();
+            for (final Options value : values()) {
+                options.add(value.getOptionName());
+            }
+            return options;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/HelpResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/HelpResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/HelpResultManager.java
new file mode 100644
index 0000000..7a67943
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/help/HelpResultManager.java
@@ -0,0 +1,25 @@
+/*
+ * 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.cli.commands.help;
+
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+
+public class HelpResultManager extends CommonsResultManager {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/Info.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/Info.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/Info.java
new file mode 100644
index 0000000..ccf9170
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/Info.java
@@ -0,0 +1,243 @@
+/*
+ * 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.cli.commands.info;
+
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.common.lib.to.SyncopeTO;
+import org.apache.syncope.common.rest.api.service.SyncopeService;
+
+public class Info {
+
+    private final SyncopeTO syncopeTO = SyncopeServices.get(SyncopeService.class).info();
+    
+    private final InfoResultManager infoResultManager = new InfoResultManager();
+
+    public void version() {
+        try {
+            infoResultManager.generic("Syncope version: " + syncopeTO.getVersion());
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void pwdResetAllowed() {
+        try {
+            infoResultManager.generic("Password reset allowed: " + syncopeTO.isPwdResetAllowed());
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void resetWithSecurityQuestion() {
+        try {
+            infoResultManager.generic("Password reset requiring security question: "
+                    + syncopeTO.isPwdResetRequiringSecurityQuestions());
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void selfRegistrationAllowed() {
+        try {
+            infoResultManager.generic("Self registration allowed: " + syncopeTO.isSelfRegAllowed());
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void provisioningManager() {
+        try {
+            infoResultManager.generic(
+                    "Any object provisioning manager class: " + syncopeTO.getAnyObjectProvisioningManager(),
+                    "User       provisioning manager class: " + syncopeTO.getUserProvisioningManager(),
+                    "Group      provisioning manager class: " + syncopeTO.getGroupProvisioningManager());
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void workflowAdapter() {
+        try {
+            infoResultManager.generic(
+                    "Any object workflow adapter class: " + syncopeTO.getAnyObjectWorkflowAdapter(),
+                    "User       workflow adapter class: " + syncopeTO.getUserWorkflowAdapter(),
+                    "Group      workflow adapter class: " + syncopeTO.getGroupWorkflowAdapter());
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void accountRules() {
+        try {
+            for (final String accountRule : syncopeTO.getAccountRules()) {
+                infoResultManager.generic("Account rule: " + accountRule);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void connidLocation() {
+        try {
+            for (final String location : syncopeTO.getConnIdLocations()) {
+                infoResultManager.generic("ConnId location: " + location);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void logicActions() {
+        try {
+            for (final String logic : syncopeTO.getLogicActions()) {
+                infoResultManager.generic("Logic action: " + logic);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void mailTemplates() {
+        try {
+            for (final String template : syncopeTO.getMailTemplates()) {
+                infoResultManager.generic("Mail template: " + template);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void mappingItemTransformers() {
+        try {
+            for (final String tranformer : syncopeTO.getMappingItemTransformers()) {
+                infoResultManager.generic("Mapping item tranformer: " + tranformer);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void passwordRules() {
+        try {
+            for (final String rules : syncopeTO.getPasswordRules()) {
+                infoResultManager.generic("Password rule: " + rules);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void propagationActions() {
+        try {
+            for (final String action : syncopeTO.getPropagationActions()) {
+                infoResultManager.generic("Propagation action: " + action);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void pushActions() {
+        try {
+            for (final String action : syncopeTO.getPushActions()) {
+                infoResultManager.generic("Push action: " + action);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void pushCorrelationActions() {
+        try {
+            for (final String rule : syncopeTO.getPushCorrelationRules()) {
+                infoResultManager.generic("Push correlation rule: " + rule);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void reportlets() {
+        try {
+            for (final String reportlet : syncopeTO.getReportlets()) {
+                infoResultManager.generic("Reportlet: " + reportlet);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void syncActions() {
+        try {
+            for (final String action : syncopeTO.getSyncActions()) {
+                infoResultManager.generic("Sync action: " + action);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void syncCorrelationRules() {
+        try {
+            for (final String rule : syncopeTO.getSyncCorrelationRules()) {
+                infoResultManager.generic("Sync correlation rule: " + rule);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void taskJobs() {
+        try {
+            for (final String job : syncopeTO.getTaskJobs()) {
+                infoResultManager.generic("Task job: " + job);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void validators() {
+        try {
+            for (final String validator : syncopeTO.getValidators()) {
+                infoResultManager.generic("Validator: " + validator);
+            }
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void passwordGenerators() {
+        try {
+            infoResultManager.generic(
+                    "Password generator class: " + syncopeTO.getPasswordGenerator());
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+
+    public void virAttrCache() {
+        try {
+            infoResultManager.generic(
+                    "Virtual attribute cache class: " + syncopeTO.getVirAttrCache());
+        } catch (final Exception ex) {
+            infoResultManager.generic(ex.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/InfoCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/InfoCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/InfoCommand.java
new file mode 100644
index 0000000..31b9aaa
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/InfoCommand.java
@@ -0,0 +1,180 @@
+/*
+ * 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.cli.commands.info;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.commands.AbstractCommand;
+import org.apache.syncope.client.cli.util.CommandUtils;
+
+@Command(name = "info")
+public class InfoCommand extends AbstractCommand {
+
+    private final Info info = new Info();
+
+    @Override
+    public void execute(final Input input) {
+        if (StringUtils.isBlank(input.getOption())) {
+            input.setOption(Options.HELP.getOptionName());
+        }
+
+        switch (Options.fromName(input.getOption())) {
+            case VERSION:
+                info.version();
+                break;
+            case PWD_RESET_ALLOWED:
+                info.pwdResetAllowed();
+                break;
+            case PWD_RESET_WITH_SECURITY_QUESTION:
+                info.resetWithSecurityQuestion();
+                break;
+            case SELF_REG_ALLOWED:
+                info.selfRegistrationAllowed();
+                break;
+            case PROVISIONING_MANAGER:
+                info.provisioningManager();
+                break;
+            case WORKFLOW_ADAPTER:
+                info.workflowAdapter();
+                break;
+            case ACCOUNT_RULES:
+                info.accountRules();
+                break;
+            case CONNID_LOCATION:
+                info.connidLocation();
+                break;
+            case LOGIC_ACTIONS:
+                info.logicActions();
+                break;
+            case MAIL_TEMPLATES:
+                info.mailTemplates();
+                break;
+            case MAPPING_ITEM_TRANSFORMERS:
+                info.mappingItemTransformers();
+                break;
+            case PASSWORD_RULES:
+                info.passwordRules();
+                break;
+            case PROPAGATION_ACTIONS:
+                info.propagationActions();
+                break;
+            case PUSH_ACTIONS:
+                info.pushActions();
+                break;
+            case PUSH_CORRELATION_ACTIONS:
+                info.pushCorrelationActions();
+                break;
+            case REPORTLETS:
+                info.reportlets();
+                break;
+            case SYNC_ACTIONS:
+                info.syncActions();
+                break;
+            case SYNC_CORRELATION_RULES:
+                info.syncCorrelationRules();
+                break;
+            case TASK_JOBS:
+                info.taskJobs();
+                break;
+            case VALIDATORS:
+                info.validators();
+                break;
+            case PASSWORD_GENERATOR:
+                info.passwordGenerators();
+                break;
+            case VIR_ATTR_CACHE:
+                info.virAttrCache();
+                break;
+            case HELP:
+                System.out.println(CommandUtils.helpMessage("info", Options.toList()));
+                break;
+            default:
+                new InfoResultManager().defaultError(
+                        input.getOption(), CommandUtils.helpMessage("info", Options.toList()));
+                break;
+        }
+    }
+
+    @Override
+    public String getHelpMessage() {
+        return CommandUtils.helpMessage("info", Options.toList());
+    }
+
+    private enum Options {
+
+        VERSION("--version"),
+        PWD_RESET_ALLOWED("--pwd-reset-allowed"),
+        PWD_RESET_WITH_SECURITY_QUESTION("--pwd-reset-with-question"),
+        SELF_REG_ALLOWED("--self-reg-allowed"),
+        PROVISIONING_MANAGER("--provisioning-manager-classes"),
+        WORKFLOW_ADAPTER("--workflow-adapter-classes"),
+        ACCOUNT_RULES("--account-rules-classes"),
+        CONNID_LOCATION("--connid-locations"),
+        LOGIC_ACTIONS("--logic-actions"),
+        MAIL_TEMPLATES("--mail-templates"),
+        MAPPING_ITEM_TRANSFORMERS("--mapping-item-transformers"),
+        PASSWORD_RULES("--password-rules"),
+        PROPAGATION_ACTIONS("--propagation-actions"),
+        PUSH_ACTIONS("--push-actions"),
+        PUSH_CORRELATION_ACTIONS("--push-correlation-actions"),
+        REPORTLETS("--reportlets"),
+        SYNC_ACTIONS("--sync-actions"),
+        SYNC_CORRELATION_RULES("--sync-correlation-rules"),
+        TASK_JOBS("--task-jobs"),
+        VALIDATORS("--validators"),
+        PASSWORD_GENERATOR("--password-generator"),
+        VIR_ATTR_CACHE("--vir-attr-cache"),
+        HELP("--help");
+
+        private final String optionName;
+
+        Options(final String optionName) {
+            this.optionName = optionName;
+        }
+
+        public String getOptionName() {
+            return optionName;
+        }
+
+        public boolean equalsOptionName(final String otherName) {
+            return (otherName == null) ? false : optionName.equals(otherName);
+        }
+
+        public static Options fromName(final String name) {
+            Options optionToReturn = HELP;
+            for (final Options option : Options.values()) {
+                if (option.equalsOptionName(name)) {
+                    optionToReturn = option;
+                }
+            }
+            return optionToReturn;
+        }
+
+        public static List<String> toList() {
+            final List<String> options = new ArrayList<>();
+            for (final Options value : values()) {
+                options.add(value.getOptionName());
+            }
+            return options;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/InfoResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/InfoResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/InfoResultManager.java
new file mode 100644
index 0000000..237af64
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/info/InfoResultManager.java
@@ -0,0 +1,25 @@
+/*
+ * 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.cli.commands.info;
+
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+
+public class InfoResultManager extends CommonsResultManager {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
index 3782eac..a8703a9 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
@@ -21,7 +21,7 @@ package org.apache.syncope.client.cli.commands.logger;
 import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.common.rest.api.service.LoggerService;
 
-public class AbstractLoggerCommand {
+public abstract class AbstractLoggerCommand {
 
     protected final LoggerService loggerService = SyncopeServices.get(LoggerService.class);
     

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
index 29d60ad..6a51e95 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
@@ -21,6 +21,7 @@ package org.apache.syncope.client.cli.commands.logger;
 import java.util.LinkedList;
 import javax.xml.ws.WebServiceException;
 import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.LoggerTO;
 import org.apache.syncope.common.lib.types.LoggerLevel;
@@ -52,7 +53,8 @@ public class LoggerCreate extends AbstractLoggerCommand {
                     loggerService.update(LoggerType.LOG, loggerTO);
                     loggerTOs.add(loggerTO);
                 } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
-                    loggerResultManager.typeNotValidError(input.firstParameter());
+                    loggerResultManager.typeNotValidError(
+                            "logger level", input.firstParameter(), CommandUtils.fromEnumToArray(LoggerLevel.class));
                     failed = true;
                     break;
                 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
index 7279b96..03de917 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
@@ -21,6 +21,7 @@ package org.apache.syncope.client.cli.commands.logger;
 import java.util.LinkedList;
 import javax.xml.ws.WebServiceException;
 import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.LoggerTO;
 import org.apache.syncope.common.lib.types.LoggerLevel;
@@ -52,7 +53,10 @@ public class LoggerUpdate extends AbstractLoggerCommand {
                     loggerTOs.add(loggerTO);
                 } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
                     if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                        loggerResultManager.typeNotValidError(input.firstParameter());
+                        loggerResultManager.typeNotValidError(
+                                "logger level",
+                                input.firstParameter(),
+                                CommandUtils.fromEnumToArray(LoggerLevel.class));
                     } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
                         loggerResultManager.generic(ex.getMessage(), UPDATE_HELP_MESSAGE);
                     } else if (ex.getMessage().startsWith("NotFound")) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
index f1c25c2..55c2e60 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
@@ -21,6 +21,7 @@ package org.apache.syncope.client.cli.commands.logger;
 import java.util.LinkedList;
 import javax.xml.ws.WebServiceException;
 import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.LoggerTO;
 import org.apache.syncope.common.lib.types.LoggerLevel;
@@ -47,7 +48,10 @@ public class LoggerUpdateAll extends AbstractLoggerCommand {
                     loggerTOs.add(loggerTO);
                 } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
                     if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                        loggerResultManager.typeNotValidError(input.firstParameter());
+                        loggerResultManager.typeNotValidError(
+                                "logger level",
+                                input.firstParameter(),
+                                CommandUtils.fromEnumToArray(LoggerLevel.class));
                     } else {
                         loggerResultManager.generic(ex.getMessage(), UPDATE_ALL_HELP_MESSAGE);
                     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/AbstractNotificationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/AbstractNotificationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/AbstractNotificationCommand.java
new file mode 100644
index 0000000..2b862ed
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/AbstractNotificationCommand.java
@@ -0,0 +1,30 @@
+/*
+ * 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.cli.commands.notification;
+
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.common.rest.api.service.NotificationService;
+
+public abstract class AbstractNotificationCommand {
+
+    protected final NotificationService notificationService = SyncopeServices.get(NotificationService.class);
+    
+    protected final NotificationResultManager notificationResultManager = new NotificationResultManager();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationCommand.java
new file mode 100644
index 0000000..d5197ac
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationCommand.java
@@ -0,0 +1,109 @@
+/*
+ * 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.cli.commands.notification;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.commands.AbstractCommand;
+
+@Command(name = "notification")
+public class NotificationCommand extends AbstractCommand {
+
+    private static final String HELP_MESSAGE = "Usage: notification [options]\n"
+            + "  Options:\n"
+            + "    --help \n"
+            + "    --list \n"
+            + "    --read \n"
+            + "       Syntax: --read {NOTIFICATION-ID} \n"
+            + "    --delete \n"
+            + "       Syntax: --delete {NOTIFICATION-ID}";
+
+    @Override
+    public void execute(final Input input) {
+        if (StringUtils.isBlank(input.getOption())) {
+            input.setOption(Options.HELP.getOptionName());
+        }
+
+        switch (Options.fromName(input.getOption())) {
+            case LIST:
+                new NotificationList().list();
+                break;
+            case READ:
+                new NotificationRead(input).read();
+                break;
+            case DELETE:
+                new NotificationDelete(input).delete();
+                break;
+            case HELP:
+                System.out.println(HELP_MESSAGE);
+                break;
+            default:
+                new NotificationResultManager().deletedMessage(input.getOption(), HELP_MESSAGE);
+        }
+    }
+
+    @Override
+    public String getHelpMessage() {
+        return HELP_MESSAGE;
+    }
+
+    private enum Options {
+
+        HELP("--help"),
+        LIST("--list"),
+        READ("--read"),
+        DELETE("--delete");
+
+        private final String optionName;
+
+        Options(final String optionName) {
+            this.optionName = optionName;
+        }
+
+        public String getOptionName() {
+            return optionName;
+        }
+
+        public boolean equalsOptionName(final String otherName) {
+            return (otherName == null) ? false : optionName.equals(otherName);
+        }
+
+        public static Options fromName(final String name) {
+            Options optionToReturn = HELP;
+            for (final Options option : Options.values()) {
+                if (option.equalsOptionName(name)) {
+                    optionToReturn = option;
+                }
+            }
+            return optionToReturn;
+        }
+
+        public static List<String> toList() {
+            final List<String> options = new ArrayList<>();
+            for (final Options value : values()) {
+                options.add(value.getOptionName());
+            }
+            return options;
+        }
+    }
+
+}


[27/54] [abbrv] syncope git commit: Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/syncope

Posted by fm...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/syncope


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

Branch: refs/heads/SYNCOPE-156
Commit: 758a3c4a863ac2192adebbc089c2aa9125a04d0e
Parents: 4d71ff3 c5923de
Author: massi <ma...@tirasa.net>
Authored: Tue Oct 20 14:59:20 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Tue Oct 20 14:59:20 2015 +0200

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------



[18/54] [abbrv] syncope git commit: Upgrading surefire, failsafe and checkstyle plugins

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
index e049a28,0000000..7bcfc10
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
@@@ -1,303 -1,0 +1,303 @@@
 +/*
 + * 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.cli.commands.install;
 +
 +import java.io.FileNotFoundException;
 +import java.io.UnsupportedEncodingException;
 +import java.net.ConnectException;
 +import java.net.UnknownHostException;
 +import java.util.Scanner;
 +import javax.ws.rs.ProcessingException;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.SyncopeServices;
 +import org.apache.syncope.client.cli.commands.AbstractCommand;
 +import org.apache.syncope.client.cli.commands.LoggerCommand;
 +import org.apache.syncope.client.cli.util.FileSystemUtils;
 +import org.apache.syncope.client.cli.util.JasyptUtils;
 +import org.apache.syncope.common.rest.api.service.SyncopeService;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +@Command(name = "install")
 +public class InstallCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
 +
 +    private static final String HELP_MESSAGE = "Usage: install [options]\n"
 +            + "  Options:\n"
 +            + "    --help \n"
 +            + "    --setup";
 +
 +    private String syncopeAdminUser;
 +
 +    private String syncopeAdminPassword;
 +
 +    private String syncopeServerSchema;
 +
 +    private String syncopeServerHostname = "localhost";
 +
 +    private String syncopeServerPort = "8080";
 +
 +    private String syncopeServerRestContext = "/syncope/rest/";
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        switch (Options.fromName(input.getOption())) {
 +            case INSTALL:
 +                final Scanner scanIn = new Scanner(System.in);
 +
 +                System.out.println("");
 +                System.out.println("###############################################");
 +                System.out.println("#                                             #");
 +                System.out.println("# Welcome to Syncope CLI installation process #");
 +                System.out.println("#                                             #");
 +                System.out.println("###############################################");
 +                System.out.println("");
 +
 +                System.out.println("Path to config files of Syncope CLI client will be: "
 +                        + InstallConfigFileTemplate.DIR_PATH);
 +
 +                if (!FileSystemUtils.canWrite(InstallConfigFileTemplate.DIR_PATH)) {
 +                    System.out.println("Permission denied on " + InstallConfigFileTemplate.DIR_PATH);
 +                    break;
 +                }
 +                System.out.println("- File system permission checked");
 +                System.out.println("");
 +
 +                System.out.println("Syncope server schema [http/https]:");
 +                String syncopeServerSchemaFromSystemIn = scanIn.nextLine();
 +                boolean schemaFounded = false;
 +                while (!schemaFounded) {
 +                    if (("http".equalsIgnoreCase(syncopeServerSchemaFromSystemIn))
 +                            || ("https".equalsIgnoreCase(syncopeServerSchemaFromSystemIn))) {
 +                        syncopeServerSchema = syncopeServerSchemaFromSystemIn;
 +                        schemaFounded = true;
 +                    } else {
 +                        System.out.println("Please use one of below values:");
 +                        System.out.println("   - http");
 +                        System.out.println("   - https");
 +                        syncopeServerSchemaFromSystemIn = scanIn.nextLine();
 +                    }
 +                }
 +
 +                System.out.println("Syncope server hostname [e.g. " + syncopeServerHostname + "]:");
 +                String syncopeServerHostnameFromSystemIn = scanIn.nextLine();
 +                boolean syncopeServerHostnameFounded = false;
 +                while (!syncopeServerHostnameFounded) {
 +                    if (StringUtils.isNotBlank(syncopeServerHostnameFromSystemIn)) {
 +                        syncopeServerHostname = syncopeServerHostnameFromSystemIn;
 +                        syncopeServerHostnameFounded = true;
 +                    } else {
 +                        System.out.println("Syncope server hostname [e.g. " + syncopeServerHostname + "]:");
 +                        syncopeServerHostnameFromSystemIn = scanIn.nextLine();
 +                    }
 +                }
 +
 +                System.out.println("Syncope server port [e.g. " + syncopeServerPort + "]:");
 +                String syncopeServerPortFromSystemIn = scanIn.nextLine();
 +                boolean syncopeServerPortFounded = false;
 +                while (!syncopeServerPortFounded) {
 +                    if (StringUtils.isNotBlank(syncopeServerPortFromSystemIn)) {
 +                        syncopeServerPort = syncopeServerPortFromSystemIn;
 +                        syncopeServerPortFounded = true;
 +                    } else if (!StringUtils.isNumeric(syncopeServerPortFromSystemIn)) {
 +                        System.out.println(syncopeServerPortFromSystemIn + " is not a numeric string, try again");
 +                        syncopeServerPortFromSystemIn = scanIn.nextLine();
 +                    } else {
 +                        System.out.println("Syncope server port [e.g. " + syncopeServerPort + "]:");
 +                        syncopeServerPortFromSystemIn = scanIn.nextLine();
 +                    }
 +                }
 +
 +                System.out.println("Syncope server rest context [e.g. " + syncopeServerRestContext + "]:");
 +                String syncopeServerRestContextFromSystemIn = scanIn.nextLine();
 +                boolean syncopeServerRestContextFounded = false;
 +                while (!syncopeServerRestContextFounded) {
 +                    if (StringUtils.isNotBlank(syncopeServerRestContextFromSystemIn)) {
 +                        syncopeServerRestContext = syncopeServerRestContextFromSystemIn;
 +                        syncopeServerRestContextFounded = true;
 +                    } else {
 +                        System.out.println("Syncope server port [e.g. " + syncopeServerRestContext + "]:");
 +                        syncopeServerRestContextFromSystemIn = scanIn.nextLine();
 +                    }
 +                }
 +
 +                System.out.println("Syncope admin user:");
 +                String syncopeAdminUserFromSystemIn = scanIn.nextLine();
 +                boolean syncopeAdminUserFounded = false;
 +                while (!syncopeAdminUserFounded) {
 +                    if (StringUtils.isNotBlank(syncopeAdminUserFromSystemIn)) {
 +                        syncopeAdminUser = syncopeAdminUserFromSystemIn;
 +                        syncopeAdminUserFounded = true;
 +                    } else {
 +                        System.out.println("Syncope admin user:");
 +                        syncopeAdminUserFromSystemIn = scanIn.nextLine();
 +                    }
 +                }
 +
 +                System.out.println("Syncope admin password:");
 +                String syncopeAdminPasswordFromSystemIn = scanIn.nextLine();
 +                boolean syncopeAdminPasswordFounded = false;
 +                while (!syncopeAdminPasswordFounded) {
 +                    if (StringUtils.isNotBlank(syncopeAdminPasswordFromSystemIn)) {
 +                        syncopeAdminPassword = syncopeAdminPasswordFromSystemIn;
 +                        syncopeAdminPasswordFounded = true;
 +                    } else {
 +                        System.out.println("Syncope admin user:");
 +                        syncopeAdminPasswordFromSystemIn = scanIn.nextLine();
 +                    }
 +                }
 +
 +                scanIn.close();
 +
 +                final JasyptUtils jasyptUtils = JasyptUtils.getJasyptUtils();
 +
 +                try {
 +                    FileSystemUtils.createNewDirectory(InstallConfigFileTemplate.DIR_PATH);
 +                    final String contentCliPropertiesFile = InstallConfigFileTemplate.createFile(
 +                            syncopeServerSchema,
 +                            syncopeServerHostname,
 +                            syncopeServerPort,
 +                            syncopeServerRestContext,
 +                            syncopeAdminUser,
 +                            jasyptUtils.encrypt(syncopeAdminPassword));
 +                    FileSystemUtils.createFileWith(InstallConfigFileTemplate.FILE_PATH, contentCliPropertiesFile);
 +
 +                } catch (final FileNotFoundException | UnsupportedEncodingException ex) {
 +                    System.out.println(ex.getMessage());
 +                }
 +
 +                try {
 +                    final SyncopeService syncopeService = SyncopeServices.get(SyncopeService.class);
 +                    System.out.println("Provided parameters checked on Syncope core version: "
 +                            + syncopeService.info().getVersion());
 +                    System.out.println("");
 +                    System.out.println("###############################################");
 +                    System.out.println("#                                             #");
 +                    System.out.println("#           Installation successful           #");
 +                    System.out.println("#     now you can use Syncope CLI client      #");
 +                    System.out.println("#                                             #");
 +                    System.out.println("###############################################");
 +                    System.out.println("");
 +                } catch (final ProcessingException ex) {
 +                    if (ex.getCause() instanceof UnknownHostException) {
 +                        final String unknownHost = ex.getCause().getMessage().split(":")[3];
 +                        System.out.println("");
 +                        System.out.println("Provided host:" + unknownHost);
 +                        System.out.println("");
 +                        System.out.println("###############################################");
 +                        System.out.println("#                                             #");
 +                        System.out.println("#            Provided unknown host!           #");
 +                        System.out.println("#        START AGAIN the installation!        #");
 +                        System.out.println("#                                             #");
 +                        System.out.println("###############################################");
 +                        System.out.println("");
 +                    } else if (ex.getCause() instanceof ConnectException) {
 +                        System.out.println("");
 +                        System.out.println("Provided address :" + SyncopeServices.getAddress());
 +                        System.out.println("");
 +                        System.out.println("###############################################");
 +                        System.out.println("#                                             #");
 +                        System.out.println("#       Provided address is unreachable!      #");
 +                        System.out.println("#         Check it and if it is wrong         #");
 +                        System.out.println("#        START AGAIN the installation!        #");
 +                        System.out.println("#                                             #");
 +                        System.out.println("###############################################");
 +                        System.out.println("");
 +                    }
 +                } catch (final Exception e) {
 +                    if (e.getMessage().contains("not authenticated")) {
 +                        System.out.println("");
 +                        System.out.println("###############################################");
 +                        System.out.println("#                                             #");
 +                        System.out.println("#   Username or password provided are wrong   #");
 +                        System.out.println("#        START AGAIN the installation!        #");
 +                        System.out.println("#                                             #");
 +                        System.out.println("###############################################");
 +                        System.out.println("");
 +                    } else {
 +                        System.out.println("");
 +                        System.out.println("###############################################");
 +                        System.out.println("#                                             #");
 +                        System.out.println("#                Something wrong              #");
 +                        System.out.println("#        START AGAIN the installation!        #");
 +                        System.out.println("#                                             #");
 +                        System.out.println("###############################################");
 +                        System.out.println("");
 +                    }
 +                }
 +                break;
 +            case HELP:
 +                System.out.println(HELP_MESSAGE);
 +                break;
 +            default:
 +                System.out.println(input.getOption() + " is not a valid option.");
 +                System.out.println("");
 +                System.out.println(HELP_MESSAGE);
 +        }
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return HELP_MESSAGE;
 +    }
 +
 +    private enum Options {
 +
 +        HELP("--help"),
 +        INSTALL("--setup");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/commons/SortableAnyProviderComparator.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/commons/SortableAnyProviderComparator.java
index 99cfaf0,0000000..68ea374
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/SortableAnyProviderComparator.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/SortableAnyProviderComparator.java
@@@ -1,122 -1,0 +1,122 @@@
 +/*
 + * 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.console.commons;
 +
 +import java.util.Arrays;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +import org.apache.syncope.common.lib.to.AnyTO;
 +import org.apache.syncope.common.lib.to.AttrTO;
 +import org.apache.syncope.common.lib.types.SchemaType;
 +import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
 +import org.apache.wicket.model.AbstractReadOnlyModel;
 +
 +public class SortableAnyProviderComparator extends SortableDataProviderComparator<AnyTO> {
 +
 +    private static final long serialVersionUID = 1775967163571699258L;
 +
 +    private static final Set<String> INLINE_PROPS = new HashSet<>(Arrays.asList(
 +            new String[] { "key", "status", "token", "username" }));
 +
 +    public SortableAnyProviderComparator(final SortableDataProvider<AnyTO, String> provider) {
 +        super(provider);
 +    }
 +
 +    @Override
 +    public int compare(final AnyTO any1, final AnyTO any2) {
 +        if (INLINE_PROPS.contains(provider.getSort().getProperty())) {
 +            return super.compare(any1, any2);
 +        }
 +
 +        return super.compare(new AttrModel(any1), new AttrModel(any2));
 +    }
 +
 +    @SuppressWarnings("rawtypes")
 +    private class AttrModel extends AbstractReadOnlyModel<Comparable> {
 +
 +        private static final long serialVersionUID = -7856686374020091808L;
 +
 +        private final Map<String, AttrTO> attrs;
 +
 +        private final Map<String, AttrTO> derAttrs;
 +
 +        private final Map<String, AttrTO> virAttrs;
 +
-         public AttrModel(final AnyTO anyTO) {
++        AttrModel(final AnyTO anyTO) {
 +            super();
 +
 +            this.attrs = anyTO.getPlainAttrMap();
 +            this.derAttrs = anyTO.getDerAttrMap();
 +            this.virAttrs = anyTO.getVirAttrMap();
 +        }
 +
 +        /**
 +         * @see UserAttrColumn constructor
 +         */
 +        @Override
 +        public Comparable getObject() {
 +            int hashPos = provider.getSort().getProperty().indexOf('#');
 +
 +            SchemaType schemaType = null;
 +            final String schema;
 +            if (hashPos == -1) {
 +                schema = provider.getSort().getProperty();
 +            } else {
 +                String[] splitted = provider.getSort().getProperty().split("#");
 +                try {
 +                    schemaType = SchemaType.valueOf(splitted[0]);
 +                } catch (IllegalArgumentException e) {
 +                    // this should never happen
 +                }
 +                schema = provider.getSort().getProperty().substring(hashPos + 1);
 +            }
 +
 +            final AttrTO attr;
 +            if (schemaType == null) {
 +                attr = this.attrs.get(schema);
 +            } else {
 +                switch (schemaType) {
 +                    case PLAIN:
 +                    default:
 +                        attr = this.attrs.get(schema);
 +                        break;
 +
 +                    case DERIVED:
 +                        attr = this.derAttrs.get(schema);
 +                        break;
 +
 +                    case VIRTUAL:
 +                        attr = this.virAttrs.get(schema);
 +                        break;
 +                }
 +            }
 +
 +            Comparable result = null;
 +
 +            List<String> values = attr == null ? null : attr.getValues();
 +            if (values != null && !values.isEmpty()) {
 +                result = values.iterator().next();
 +            }
 +
 +            return result;
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/commons/status/Status.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/commons/status/Status.java
index 7198c2c,0000000..56b6992
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/Status.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/Status.java
@@@ -1,45 -1,0 +1,45 @@@
 +/*
 + * 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.console.commons.status;
 +
 +public enum Status {
 +
 +    NOT_YET_SUBMITTED(""),
 +    CREATED("created"),
 +    ACTIVE("active"),
 +    SUSPENDED("inactive"),
 +    UNDEFINED("undefined"),
 +    OBJECT_NOT_FOUND("objectnotfound");
 +
 +    public boolean isActive() {
 +        return this == ACTIVE;
 +    }
 +
-     private Status(final String name) {
++    Status(final String name) {
 +        this.name = name;
 +    }
 +
 +    private final String name;
 +
 +    @Override
 +    public String toString() {
 +        return name;
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/pages/Login.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/pages/Login.java
index 23fb25f,0000000..99cd6d3
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/Login.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/Login.java
@@@ -1,210 -1,0 +1,210 @@@
 +/*
 + * 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.console.pages;
 +
 +import java.security.AccessControlException;
 +import java.util.Locale;
 +import org.apache.syncope.client.console.SyncopeConsoleApplication;
 +import org.apache.syncope.client.console.SyncopeConsoleSession;
 +import org.apache.syncope.client.console.commons.Constants;
 +import org.apache.syncope.client.console.panels.NotificationPanel;
 +import org.apache.syncope.common.lib.SyncopeConstants;
 +import org.apache.wicket.ajax.AjaxRequestTarget;
 +import org.apache.wicket.ajax.markup.html.form.AjaxButton;
 +import org.apache.wicket.authentication.IAuthenticationStrategy;
 +import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
 +import org.apache.wicket.markup.html.WebPage;
 +import org.apache.wicket.markup.html.form.ChoiceRenderer;
 +import org.apache.wicket.markup.html.form.DropDownChoice;
 +import org.apache.wicket.markup.html.form.Form;
 +import org.apache.wicket.markup.html.form.PasswordTextField;
 +import org.apache.wicket.markup.html.form.StatelessForm;
 +import org.apache.wicket.markup.html.form.TextField;
 +import org.apache.wicket.model.IModel;
 +import org.apache.wicket.model.Model;
 +import org.apache.wicket.request.mapper.parameter.PageParameters;
 +import org.apache.wicket.spring.injection.annot.SpringBean;
 +
 +public class Login extends WebPage {
 +
 +    private static final long serialVersionUID = 5889157642852559004L;
 +
 +    @SpringBean(name = "anonymousUser")
 +    private String anonymousUser;
 +
 +    private final NotificationPanel feedbackPanel;
 +
 +    private final StatelessForm<Void> form;
 +
 +    private final TextField<String> usernameField;
 +
 +    private final TextField<String> passwordField;
 +
 +    private final DropDownChoice<Locale> languageSelect;
 +
 +    private final DropDownChoice<String> domainSelect;
 +
 +    public Login(final PageParameters parameters) {
 +        super(parameters);
 +        setStatelessHint(true);
 +
 +        feedbackPanel = new NotificationPanel(Constants.FEEDBACK);
 +        add(feedbackPanel);
 +
 +        form = new StatelessForm<>("login");
 +
 +        usernameField = new TextField<>("username", new Model<String>());
 +        usernameField.setMarkupId("username");
 +        form.add(usernameField);
 +
 +        passwordField = new PasswordTextField("password", new Model<String>());
 +        passwordField.setMarkupId("password");
 +        form.add(passwordField);
 +
 +        languageSelect = new LocaleDropDown("language");
 +        form.add(languageSelect);
 +
 +        domainSelect = new DomainDropDown("domain");
 +        if (SyncopeConsoleSession.get().getDomains().size() == 1) {
 +            domainSelect.setOutputMarkupPlaceholderTag(true);
 +        }
 +        form.add(domainSelect);
 +
 +        AjaxButton submitButton = new AjaxButton("submit", new Model<>(getString("submit"))) {
 +
 +            private static final long serialVersionUID = 429178684321093953L;
 +
 +            @Override
 +            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
 +                if (anonymousUser.equals(usernameField.getRawInput())) {
 +                    throw new AccessControlException("Illegal username");
 +                }
 +
 +                IAuthenticationStrategy strategy = getApplication().getSecuritySettings().getAuthenticationStrategy();
 +
 +                if (AuthenticatedWebSession.get().signIn(usernameField.getRawInput(), passwordField.getRawInput())) {
 +                    // If login has been called because the user was not yet logged in, than continue to the
 +                    // original destination, otherwise to the Home page
 +                    continueToOriginalDestination();
 +                    setResponsePage(getApplication().getHomePage());
 +                } else {
 +                    error(getString("login-error"));
 +                    feedbackPanel.refresh(target);
 +                }
 +                strategy.remove();
 +            }
 +        };
 +        submitButton.setDefaultFormProcessing(false);
 +        form.add(submitButton);
 +        form.setDefaultButton(submitButton);
 +
 +        add(form);
 +    }
 +
 +    /**
 +     * Inner class which implements (custom) Locale DropDownChoice component.
 +     */
 +    private class LocaleDropDown extends DropDownChoice<Locale> {
 +
 +        private static final long serialVersionUID = 2349382679992357202L;
 +
 +        private class LocaleRenderer extends ChoiceRenderer<Locale> {
 +
 +            private static final long serialVersionUID = -3657529581555164741L;
 +
 +            @Override
 +            public String getDisplayValue(final Locale locale) {
 +                return locale.getDisplayName(getLocale());
 +            }
 +        }
 +
-         public LocaleDropDown(final String id) {
++        LocaleDropDown(final String id) {
 +            super(id, SyncopeConsoleApplication.SUPPORTED_LOCALES);
 +
 +            setChoiceRenderer(new LocaleRenderer());
 +            setModel(new IModel<Locale>() {
 +
 +                private static final long serialVersionUID = -6985170095629312963L;
 +
 +                @Override
 +                public Locale getObject() {
 +                    return getSession().getLocale();
 +                }
 +
 +                @Override
 +                public void setObject(final Locale object) {
 +                    getSession().setLocale(object);
 +                }
 +
 +                @Override
 +                public void detach() {
 +                    // Empty.
 +                }
 +            });
 +
 +            // set default value to English
 +            getModel().setObject(Locale.ENGLISH);
 +        }
 +
 +        @Override
 +        protected boolean wantOnSelectionChangedNotifications() {
 +            return true;
 +        }
 +    }
 +
 +    /**
 +     * Inner class which implements (custom) Domain DropDownChoice component.
 +     */
 +    private class DomainDropDown extends DropDownChoice<String> {
 +
 +        private static final long serialVersionUID = -7401167913360133325L;
 +
-         public DomainDropDown(final String id) {
++        DomainDropDown(final String id) {
 +            super(id, SyncopeConsoleSession.get().getDomains());
 +
 +            setModel(new IModel<String>() {
 +
 +                private static final long serialVersionUID = -1124206668056084806L;
 +
 +                @Override
 +                public String getObject() {
 +                    return SyncopeConsoleSession.get().getDomain();
 +                }
 +
 +                @Override
 +                public void setObject(final String object) {
 +                    SyncopeConsoleSession.get().setDomain(object);
 +                }
 +
 +                @Override
 +                public void detach() {
 +                    // Empty.
 +                }
 +            });
 +
 +            // set default value to Master Domain
 +            getModel().setObject(SyncopeConstants.MASTER_DOMAIN);
 +        }
 +
 +        @Override
 +        protected boolean wantOnSelectionChangedNotifications() {
 +            return true;
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
index b631210,0000000..c66d650
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
@@@ -1,252 -1,0 +1,252 @@@
 +/*
 + * 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.console.pages;
 +
 +import java.io.Serializable;
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.LinkedHashMap;
 +import java.util.List;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.console.commons.Constants;
 +import org.apache.syncope.client.console.commons.status.AbstractStatusBeanProvider;
 +import org.apache.syncope.client.console.commons.status.ConnObjectWrapper;
 +import org.apache.syncope.client.console.commons.status.StatusBean;
 +import org.apache.syncope.client.console.commons.status.StatusUtils;
 +import org.apache.syncope.client.console.panels.ActionDataTablePanel;
 +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 +import org.apache.syncope.client.lib.SyncopeClient;
 +import org.apache.syncope.common.lib.to.AnyTO;
 +import org.apache.syncope.common.lib.to.BulkActionResult;
 +import org.apache.syncope.common.lib.to.ResourceTO;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.ResourceDeassociationAction;
 +import org.apache.syncope.common.lib.wrap.AbstractWrappable;
 +import org.apache.syncope.common.lib.wrap.AnyKey;
 +import org.apache.wicket.PageReference;
 +import org.apache.wicket.ajax.AjaxRequestTarget;
 +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
 +import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
 +import org.apache.wicket.markup.html.basic.Label;
 +import org.apache.wicket.markup.repeater.Item;
 +import org.apache.wicket.model.IModel;
 +import org.apache.wicket.model.StringResourceModel;
 +
 +public class ProvisioningModalPage<T extends AnyTO> extends AbstractStatusModalPage {
 +
 +    private static final long serialVersionUID = -4285220460543213901L;
 +
 +    private static final int ROWS_PER_PAGE = 10;
 +
 +    private final ResourceTO resourceTO;
 +
 +    private final AnyTypeKind anyTypeKind;
 +
 +    private final PageReference pageRef;
 +
 +    private final ModalWindow window;
 +
 +    private final StatusUtils statusUtils;
 +
 +    private final String realm = "/";
 +
 +    public ProvisioningModalPage(
 +            final PageReference pageRef,
 +            final ModalWindow window,
 +            final ResourceTO resourceTO,
 +            final AnyTypeKind anyTypeKind) {
 +
 +        super();
 +
 +        this.pageRef = pageRef;
 +        this.window = window;
 +        this.resourceTO = resourceTO;
 +        this.anyTypeKind = anyTypeKind;
 +
 +        statusUtils = new StatusUtils(anyTypeKind == AnyTypeKind.USER ? userRestClient : groupRestClient);
 +
 +        add(new Label("displayName", StringUtils.EMPTY));
 +
 +        final List<IColumn<StatusBean, String>> columns = new ArrayList<>();
 +        columns.add(new PropertyColumn<StatusBean, String>(
 +                new StringResourceModel("key", this).setDefaultValue("Attributable key"),
 +                "attributableKey", "attributableKey"));
 +        columns.add(new PropertyColumn<StatusBean, String>(
 +                new StringResourceModel("name", this).setDefaultValue("Attributable name"),
 +                "attributableName", "attributableName"));
 +        columns.add(new PropertyColumn<StatusBean, String>(
 +                new StringResourceModel("resourceName", this).setDefaultValue("Resource name"),
 +                "resourceName", "resourceName"));
 +        columns.add(new PropertyColumn<StatusBean, String>(
 +                new StringResourceModel("connObjectLink", this).setDefaultValue("ConnObjectLink"),
 +                "connObjectLink", "connObjectLink"));
 +        columns.add(new AbstractColumn<StatusBean, String>(
 +                new StringResourceModel("status", this).setDefaultValue(StringUtils.EMPTY)) {
 +
 +                    private static final long serialVersionUID = -3503023501954863131L;
 +
 +                    @Override
 +                    public String getCssClass() {
 +                        return "action";
 +                    }
 +
 +                    @Override
 +                    public void populateItem(
 +                            final Item<ICellPopulator<StatusBean>> cellItem,
 +                            final String componentId,
 +                            final IModel<StatusBean> model) {
 +                                cellItem.
 +                                add(statusUtils.getStatusImagePanel(componentId, model.getObject().getStatus()));
 +                            }
 +                });
 +
 +        final ActionDataTablePanel<StatusBean, String> table = new ActionDataTablePanel<>(
 +                "resourceDatatable",
 +                columns,
 +                (ISortableDataProvider<StatusBean, String>) new StatusBeanProvider(),
 +                ROWS_PER_PAGE,
 +                pageRef);
 +
 +        final String pageId = "Resources";
 +
 +        table.addAction(new ActionLink<Serializable>() {
 +
 +            private static final long serialVersionUID = -3722207913631435501L;
 +
 +            @Override
 +            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                try {
 +                    bulkAssociationAction(target, ResourceDeassociationAction.UNLINK, table, columns);
 +                } catch (Exception e) {
 +                    LOG.error("Error unlinkink resources", e);
 +                    error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                    feedbackPanel.refresh(target);
 +                }
 +            }
 +        }, ActionLink.ActionType.UNLINK, pageId);
 +
 +        table.addAction(new ActionLink<Serializable>() {
 +
 +            private static final long serialVersionUID = -3722207913631435501L;
 +
 +            @Override
 +            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                try {
 +                    bulkAssociationAction(target, ResourceDeassociationAction.DEPROVISION, table, columns);
 +                } catch (Exception e) {
 +                    LOG.error("Error de-provisioning user", e);
 +                    error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                    feedbackPanel.refresh(target);
 +                }
 +            }
 +        }, ActionLink.ActionType.DEPROVISION, pageId);
 +
 +        table.addAction(new ActionLink<Serializable>() {
 +
 +            private static final long serialVersionUID = -3722207913631435501L;
 +
 +            @Override
 +            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                try {
 +                    bulkAssociationAction(target, ResourceDeassociationAction.UNASSIGN, table, columns);
 +                } catch (Exception e) {
 +                    LOG.error("Error unassigning resources", e);
 +                    error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                    feedbackPanel.refresh(target);
 +                }
 +            }
 +        }, ActionLink.ActionType.UNASSIGN, pageId);
 +
 +        table.addCancelButton(window);
 +
 +        add(table);
 +    }
 +
 +    private class StatusBeanProvider extends AbstractStatusBeanProvider {
 +
 +        private static final long serialVersionUID = 4287357360778016173L;
 +
-         public StatusBeanProvider() {
++        StatusBeanProvider() {
 +            super("accountLink");
 +        }
 +
 +        @SuppressWarnings("unchecked")
 +        @Override
 +        public List<StatusBean> getStatusBeans() {
 +            final String fiql = SyncopeClient.getUserSearchConditionBuilder().hasResources(resourceTO.getKey()).query();
 +
 +            final List<T> subjects = new ArrayList<>();
 +            if (anyTypeKind == AnyTypeKind.USER) {
 +                subjects.addAll((List<T>) userRestClient.search(
 +                        realm, fiql, 1, ROWS_PER_PAGE, new SortParam<>("key", true), AnyTypeKind.USER.toString()));
 +            } else {
 +                subjects.addAll((List<T>) groupRestClient.search(
 +                        realm, fiql, 1, ROWS_PER_PAGE, new SortParam<>("key", true), AnyTypeKind.GROUP.toString()));
 +            }
 +
 +            final List<ConnObjectWrapper> connObjects = statusUtils.getConnectorObjects(
 +                    (List<AnyTO>) subjects, Collections.<String>singleton(resourceTO.getKey()));
 +
 +            final List<StatusBean> statusBeans = new ArrayList<>(connObjects.size() + 1);
 +            final LinkedHashMap<String, StatusBean> initialStatusBeanMap = new LinkedHashMap<>(connObjects.size());
 +
 +            for (ConnObjectWrapper entry : connObjects) {
 +                StatusBean statusBean = statusUtils.getStatusBean(entry.getAny(),
 +                        entry.getResourceName(),
 +                        entry.getConnObjectTO(),
 +                        anyTypeKind == AnyTypeKind.GROUP);
 +
 +                initialStatusBeanMap.put(entry.getResourceName(), statusBean);
 +                statusBeans.add(statusBean);
 +            }
 +
 +            return statusBeans;
 +        }
 +    }
 +
 +    private void bulkAssociationAction(
 +            final AjaxRequestTarget target,
 +            final ResourceDeassociationAction type,
 +            final ActionDataTablePanel<StatusBean, String> table,
 +            final List<IColumn<StatusBean, String>> columns) {
 +
 +        final List<StatusBean> beans = new ArrayList<>(table.getModelObject());
 +        List<AnyKey> subjectKeys = new ArrayList<>();
 +        for (StatusBean bean : beans) {
 +            LOG.debug("Selected bean {}", bean);
 +            subjectKeys.add(AbstractWrappable.getInstance(AnyKey.class, bean.getAnyKey()));
 +        }
 +
 +        if (beans.isEmpty()) {
 +            window.close(target);
 +        } else {
 +            final BulkActionResult res = resourceRestClient.bulkAssociationAction(
 +                    resourceTO.getKey(), anyTypeKind.name(), type, subjectKeys);
 +
 +            ((BasePage) pageRef.getPage()).setModalResult(true);
 +
 +            setResponsePage(new BulkActionResultModalPage<>(window, beans, columns, res, "anyKey"));
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
index 1357cad,0000000..238f13d
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
@@@ -1,642 -1,0 +1,642 @@@
 +/*
 + * 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.console.pages;
 +
 +import java.io.Serializable;
 +import java.util.ArrayList;
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.List;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.console.commons.Constants;
 +import org.apache.syncope.client.console.commons.status.AbstractStatusBeanProvider;
 +import org.apache.syncope.client.console.commons.status.ConnObjectWrapper;
 +import org.apache.syncope.client.console.commons.status.Status;
 +import org.apache.syncope.client.console.commons.status.StatusBean;
 +import org.apache.syncope.client.console.commons.status.StatusUtils;
 +import org.apache.syncope.client.console.panels.ActionDataTablePanel;
 +import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxButton;
 +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
 +import org.apache.syncope.common.lib.to.AnyTO;
 +import org.apache.syncope.common.lib.to.BulkActionResult;
 +import org.apache.syncope.common.lib.to.ResourceTO;
 +import org.apache.syncope.common.lib.to.GroupTO;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.types.ResourceAssociationAction;
 +import org.apache.wicket.PageReference;
 +import org.apache.wicket.ajax.AjaxRequestTarget;
 +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
 +import org.apache.wicket.markup.ComponentTag;
 +import org.apache.wicket.markup.html.WebMarkupContainer;
 +import org.apache.wicket.markup.html.basic.Label;
 +import org.apache.wicket.markup.html.form.Form;
 +import org.apache.wicket.markup.html.form.PasswordTextField;
 +import org.apache.wicket.markup.html.panel.Fragment;
 +import org.apache.wicket.markup.repeater.Item;
 +import org.apache.wicket.model.IModel;
 +import org.apache.wicket.model.Model;
 +import org.apache.wicket.model.ResourceModel;
 +import org.apache.wicket.model.StringResourceModel;
 +
 +public class StatusModalPage<T extends AnyTO> extends AbstractStatusModalPage {
 +
 +    private static final long serialVersionUID = -9148734710505211261L;
 +
 +    private final AnyTO anyTO;
 +
 +    private int rowsPerPage = 10;
 +
 +    private final StatusUtils statusUtils;
 +
 +    private final boolean statusOnly;
 +
 +    // --------------------------------
 +    // password management fields ..
 +    // --------------------------------
 +    private final ClearIndicatingAjaxButton cancel;
 +
 +    private final WebMarkupContainer pwdMgt;
 +
 +    private final Form<?> pwdMgtForm;
 +
 +    private final AjaxCheckBoxPanel changepwd;
 +
 +    private final PasswordTextField password;
 +
 +    private final PasswordTextField confirm;
 +    // --------------------------------
 +
 +    private final PageReference pageRef;
 +
 +    private final ModalWindow window;
 +
 +    private final ActionDataTablePanel<StatusBean, String> table;
 +
 +    private final List<IColumn<StatusBean, String>> columns;
 +
 +    public StatusModalPage(
 +            final PageReference pageRef,
 +            final ModalWindow window,
 +            final AnyTO attributableTO) {
 +
 +        this(pageRef, window, attributableTO, false);
 +    }
 +
 +    public StatusModalPage(
 +            final PageReference pageRef,
 +            final ModalWindow window,
 +            final AnyTO anyTO,
 +            final boolean statusOnly) {
 +
 +        super();
 +
 +        this.pageRef = pageRef;
 +        this.window = window;
 +        this.statusOnly = statusOnly;
 +        this.anyTO = anyTO;
 +
 +        statusUtils = new StatusUtils(anyTO instanceof UserTO ? userRestClient : groupRestClient);
 +
 +        add(new Label("displayName", anyTO.getKey() + " "
 +                + (anyTO instanceof UserTO ? ((UserTO) anyTO).getUsername() : ((GroupTO) anyTO).getName())));
 +
 +        columns = new ArrayList<>();
 +        columns.add(new AbstractColumn<StatusBean, String>(
 +                new StringResourceModel("resourceName", this, null), "resourceName") {
 +
 +                    private static final long serialVersionUID = 2054811145491901166L;
 +
 +                    @Override
 +                    public void populateItem(
 +                            final Item<ICellPopulator<StatusBean>> cellItem,
 +                            final String componentId,
 +                            final IModel<StatusBean> model) {
 +
 +                                cellItem.add(new Label(componentId, model.getObject().getResourceName()) {
 +
 +                                    private static final long serialVersionUID = 8432079838783825801L;
 +
 +                                    @Override
 +                                    protected void onComponentTag(final ComponentTag tag) {
 +                                        if (model.getObject().isLinked()) {
 +                                            super.onComponentTag(tag);
 +                                        } else {
 +                                            tag.put("style", "color: #DDDDDD");
 +                                        }
 +                                    }
 +                                });
 +                            }
 +                });
 +
 +        columns.add(new PropertyColumn<StatusBean, String>(
 +                new StringResourceModel("accountLink", this, null), "accountLink", "accountLink"));
 +
 +        columns.add(new AbstractColumn<StatusBean, String>(
 +                new StringResourceModel("status", this, null)) {
 +
 +                    private static final long serialVersionUID = -3503023501954863131L;
 +
 +                    @Override
 +                    public String getCssClass() {
 +                        return "action";
 +                    }
 +
 +                    @Override
 +                    public void populateItem(
 +                            final Item<ICellPopulator<StatusBean>> cellItem,
 +                            final String componentId,
 +                            final IModel<StatusBean> model) {
 +
 +                                if (model.getObject().isLinked()) {
 +                                    cellItem.add(statusUtils.getStatusImagePanel(componentId, model.getObject().
 +                                                    getStatus()));
 +                                } else {
 +                                    cellItem.add(new Label(componentId, ""));
 +                                }
 +                            }
 +                });
 +
 +        table = new ActionDataTablePanel<StatusBean, String>(
 +                "resourceDatatable",
 +                columns,
 +                (ISortableDataProvider<StatusBean, String>) new AttributableStatusProvider(),
 +                rowsPerPage,
 +                pageRef) {
 +
 +                    private static final long serialVersionUID = 6510391461033818316L;
 +
 +                    @Override
 +                    public boolean isElementEnabled(final StatusBean element) {
 +                        return !statusOnly || element.getStatus() != Status.OBJECT_NOT_FOUND;
 +                    }
 +                };
 +        table.setOutputMarkupId(true);
 +
 +        final String pageId = anyTO instanceof GroupTO ? "Groups" : "Users";
 +
 +        final Fragment pwdMgtFragment = new Fragment("pwdMgtFields", "pwdMgtFragment", this);
 +        addOrReplace(pwdMgtFragment);
 +
 +        pwdMgt = new WebMarkupContainer("pwdMgt");
 +        pwdMgtFragment.add(pwdMgt.setOutputMarkupId(true));
 +
 +        pwdMgtForm = new Form("pwdMgtForm");
 +        pwdMgtForm.setVisible(false).setEnabled(false);
 +        pwdMgt.add(pwdMgtForm);
 +
 +        password = new PasswordTextField("password", new Model<String>());
 +        pwdMgtForm.add(password.setRequired(false).setEnabled(false));
 +
 +        confirm = new PasswordTextField("confirm", new Model<String>());
 +        pwdMgtForm.add(confirm.setRequired(false).setEnabled(false));
 +
 +        changepwd = new AjaxCheckBoxPanel("changepwd", "changepwd", new Model<Boolean>(false));
 +        pwdMgtForm.add(changepwd.setModelObject(false));
 +        pwdMgtForm.add(new Label("changePwdLabel", new ResourceModel("changePwdLabel", "Password propagation")));
 +
 +        changepwd.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
 +
 +            private static final long serialVersionUID = -1107858522700306810L;
 +
 +            @Override
 +            protected void onUpdate(final AjaxRequestTarget target) {
 +                password.setEnabled(changepwd.getModelObject());
 +                confirm.setEnabled(changepwd.getModelObject());
 +                target.add(pwdMgt);
 +            }
 +        });
 +
 +        cancel = new ClearIndicatingAjaxButton("cancel", new ResourceModel("cancel"), pageRef) {
 +
 +            private static final long serialVersionUID = -2341391430136818026L;
 +
 +            @Override
 +            protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
 +                // ignore
 +                window.close(target);
 +            }
 +        }.feedbackPanelAutomaticReload(false);
 +
 +        pwdMgtForm.add(cancel);
 +
 +        final ClearIndicatingAjaxButton goon =
 +                new ClearIndicatingAjaxButton("continue", new ResourceModel("continue"), pageRef) {
 +
 +                    private static final long serialVersionUID = -2341391430136818027L;
 +
 +                    @Override
 +                    protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
 +                        // none
 +                    }
 +                };
 +
 +        pwdMgtForm.add(goon);
 +
 +        if (statusOnly) {
 +            table.addAction(new ActionLink<Serializable>() {
 +
 +                private static final long serialVersionUID = -3722207913631435501L;
 +
 +                @Override
 +                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                    try {
 +                        userRestClient.reactivate(
 +                                anyTO.getETagValue(),
 +                                anyTO.getKey(),
 +                                new ArrayList<>(table.getModelObject()));
 +
 +                        ((BasePage) pageRef.getPage()).setModalResult(true);
 +
 +                        window.close(target);
 +                    } catch (Exception e) {
 +                        LOG.error("Error enabling resources", e);
 +                        error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                        feedbackPanel.refresh(target);
 +                    }
 +                }
 +            }, ActionLink.ActionType.REACTIVATE, pageId);
 +
 +            table.addAction(new ActionLink<Serializable>() {
 +
 +                private static final long serialVersionUID = -3722207913631435501L;
 +
 +                @Override
 +                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                    try {
 +                        userRestClient.suspend(
 +                                anyTO.getETagValue(),
 +                                anyTO.getKey(),
 +                                new ArrayList<>(table.getModelObject()));
 +
 +                        if (pageRef.getPage() instanceof BasePage) {
 +                            ((BasePage) pageRef.getPage()).setModalResult(true);
 +                        }
 +
 +                        window.close(target);
 +                    } catch (Exception e) {
 +                        LOG.error("Error disabling resources", e);
 +                        error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                        feedbackPanel.refresh(target);
 +                    }
 +                }
 +            }, ActionLink.ActionType.SUSPEND, pageId);
 +        } else {
 +            table.addAction(new ActionLink<Serializable>() {
 +
 +                private static final long serialVersionUID = -3722207913631435501L;
 +
 +                @Override
 +                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                    try {
 +                        if (anyTO instanceof UserTO) {
 +                            userRestClient.unlink(
 +                                    anyTO.getETagValue(),
 +                                    anyTO.getKey(),
 +                                    new ArrayList<>(table.getModelObject()));
 +                        } else {
 +                            groupRestClient.unlink(
 +                                    anyTO.getETagValue(),
 +                                    anyTO.getKey(),
 +                                    new ArrayList<>(table.getModelObject()));
 +                        }
 +
 +                        ((BasePage) pageRef.getPage()).setModalResult(true);
 +                        window.close(target);
 +                    } catch (Exception e) {
 +                        LOG.error("Error unlinking resources", e);
 +                        error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                        feedbackPanel.refresh(target);
 +                    }
 +                }
 +            }, ActionLink.ActionType.UNLINK, pageId);
 +
 +            table.addAction(new ActionLink<Serializable>() {
 +
 +                private static final long serialVersionUID = -3722207913631435501L;
 +
 +                @Override
 +                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                    try {
 +                        if (anyTO instanceof UserTO) {
 +                            userRestClient.link(
 +                                    anyTO.getETagValue(),
 +                                    anyTO.getKey(),
 +                                    new ArrayList<>(table.getModelObject()));
 +                        } else {
 +                            groupRestClient.link(
 +                                    anyTO.getETagValue(),
 +                                    anyTO.getKey(),
 +                                    new ArrayList<>(table.getModelObject()));
 +                        }
 +
 +                        ((BasePage) pageRef.getPage()).setModalResult(true);
 +                        window.close(target);
 +                    } catch (Exception e) {
 +                        LOG.error("Error linking resources", e);
 +                        error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                        feedbackPanel.refresh(target);
 +                    }
 +                }
 +            }, ActionLink.ActionType.LINK, pageId);
 +
 +            table.addAction(new ActionLink<Serializable>() {
 +
 +                private static final long serialVersionUID = -3722207913631435501L;
 +
 +                @Override
 +                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                    try {
 +                        BulkActionResult bulkActionResult;
 +                        if (anyTO instanceof UserTO) {
 +                            bulkActionResult = userRestClient.deprovision(
 +                                    anyTO.getETagValue(),
 +                                    anyTO.getKey(),
 +                                    new ArrayList<>(table.getModelObject()));
 +                        } else {
 +                            bulkActionResult = groupRestClient.deprovision(
 +                                    anyTO.getETagValue(),
 +                                    anyTO.getKey(),
 +                                    new ArrayList<>(table.getModelObject()));
 +                        }
 +
 +                        ((BasePage) pageRef.getPage()).setModalResult(true);
 +                        loadBulkActionResultPage(table.getModelObject(), bulkActionResult);
 +                    } catch (Exception e) {
 +                        LOG.error("Error de-provisioning user", e);
 +                        error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                        feedbackPanel.refresh(target);
 +                    }
 +                }
 +            }, ActionLink.ActionType.DEPROVISION, pageId);
 +
 +            table.addAction(new ActionLink<Serializable>() {
 +
 +                private static final long serialVersionUID = -3722207913631435501L;
 +
 +                @Override
 +                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +
 +                    if (anyTO instanceof UserTO) {
 +                        StatusModalPage.this.passwordManagement(
 +                                target, ResourceAssociationAction.PROVISION, table.getModelObject());
 +                    } else {
 +                        try {
 +                            final BulkActionResult bulkActionResult = groupRestClient.provision(
 +                                    anyTO.getETagValue(),
 +                                    anyTO.getKey(),
 +                                    new ArrayList<>(table.getModelObject()));
 +
 +                            ((BasePage) pageRef.getPage()).setModalResult(true);
 +                            loadBulkActionResultPage(table.getModelObject(), bulkActionResult);
 +                        } catch (Exception e) {
 +                            LOG.error("Error provisioning user", e);
 +                            error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                            feedbackPanel.refresh(target);
 +                        }
 +                    }
 +                }
 +            }.feedbackPanelAutomaticReload(!(anyTO instanceof UserTO)), ActionLink.ActionType.PROVISION, pageId);
 +
 +            table.addAction(new ActionLink<Serializable>() {
 +
 +                private static final long serialVersionUID = -3722207913631435501L;
 +
 +                @Override
 +                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                    try {
 +                        final BulkActionResult bulkActionResult;
 +                        if (anyTO instanceof UserTO) {
 +                            bulkActionResult = userRestClient.unassign(
 +                                    anyTO.getETagValue(),
 +                                    anyTO.getKey(),
 +                                    new ArrayList<>(table.getModelObject()));
 +                        } else {
 +                            bulkActionResult = groupRestClient.unassign(
 +                                    anyTO.getETagValue(),
 +                                    anyTO.getKey(),
 +                                    new ArrayList<>(table.getModelObject()));
 +                        }
 +
 +                        ((BasePage) pageRef.getPage()).setModalResult(true);
 +                        loadBulkActionResultPage(table.getModelObject(), bulkActionResult);
 +                    } catch (Exception e) {
 +                        LOG.error("Error unassigning resources", e);
 +                        error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                        feedbackPanel.refresh(target);
 +                    }
 +                }
 +            }, ActionLink.ActionType.UNASSIGN, pageId);
 +
 +            table.addAction(new ActionLink<Serializable>() {
 +
 +                private static final long serialVersionUID = -3722207913631435501L;
 +
 +                @Override
 +                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                    if (anyTO instanceof UserTO) {
 +                        StatusModalPage.this.passwordManagement(
 +                                target, ResourceAssociationAction.ASSIGN, table.getModelObject());
 +                    } else {
 +                        try {
 +                            final BulkActionResult bulkActionResult = groupRestClient.assign(
 +                                    anyTO.getETagValue(),
 +                                    anyTO.getKey(),
 +                                    new ArrayList<>(table.getModelObject()));
 +
 +                            ((BasePage) pageRef.getPage()).setModalResult(true);
 +                            loadBulkActionResultPage(table.getModelObject(), bulkActionResult);
 +                        } catch (Exception e) {
 +                            LOG.error("Error assigning resources", e);
 +                            error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                            feedbackPanel.refresh(target);
 +                        }
 +                    }
 +                }
 +            }.feedbackPanelAutomaticReload(!(anyTO instanceof UserTO)), ActionLink.ActionType.ASSIGN, pageId);
 +        }
 +
 +        table.addCancelButton(window);
 +        add(table);
 +    }
 +
 +    private class AttributableStatusProvider extends AbstractStatusBeanProvider {
 +
 +        private static final long serialVersionUID = 4586969457669796621L;
 +
-         public AttributableStatusProvider() {
++        AttributableStatusProvider() {
 +            super(statusOnly ? "resourceName" : "accountLink");
 +        }
 +
 +        @SuppressWarnings("unchecked")
 +        @Override
 +        public List<StatusBean> getStatusBeans() {
 +            final List<String> resources = new ArrayList<>();
 +            for (ResourceTO resourceTO : resourceRestClient.getAll()) {
 +                resources.add(resourceTO.getKey());
 +            }
 +
 +            final List<ConnObjectWrapper> connObjects = statusUtils.getConnectorObjects(anyTO);
 +
 +            final List<StatusBean> statusBeans = new ArrayList<StatusBean>(connObjects.size() + 1);
 +
 +            for (ConnObjectWrapper entry : connObjects) {
 +                final StatusBean statusBean = statusUtils.getStatusBean(anyTO,
 +                        entry.getResourceName(),
 +                        entry.getConnObjectTO(),
 +                        anyTO instanceof GroupTO);
 +
 +                statusBeans.add(statusBean);
 +                resources.remove(entry.getResourceName());
 +            }
 +
 +            if (statusOnly) {
 +                final StatusBean syncope = new StatusBean(anyTO, "Syncope");
 +
 +                syncope.setConnObjectLink(((UserTO) anyTO).getUsername());
 +
 +                Status syncopeStatus = Status.UNDEFINED;
 +                if (((UserTO) anyTO).getStatus() != null) {
 +                    try {
 +                        syncopeStatus = Status.valueOf(((UserTO) anyTO).getStatus().toUpperCase());
 +                    } catch (IllegalArgumentException e) {
 +                        LOG.warn("Unexpected status found: {}", ((UserTO) anyTO).getStatus(), e);
 +                    }
 +                }
 +                syncope.setStatus(syncopeStatus);
 +
 +                statusBeans.add(syncope);
 +            } else {
 +                for (String resource : resources) {
 +                    final StatusBean statusBean = statusUtils.getStatusBean(anyTO,
 +                            resource,
 +                            null,
 +                            anyTO instanceof GroupTO);
 +
 +                    statusBean.setLinked(false);
 +                    statusBeans.add(statusBean);
 +                }
 +            }
 +
 +            return statusBeans;
 +        }
 +    }
 +
 +    private void passwordManagement(
 +            final AjaxRequestTarget target,
 +            final ResourceAssociationAction type,
 +            final Collection<StatusBean> selection) {
 +
 +        final ClearIndicatingAjaxButton goon =
 +                new ClearIndicatingAjaxButton("continue", new ResourceModel("continue", "Continue"), pageRef) {
 +
 +                    private static final long serialVersionUID = -2341391430136818027L;
 +
 +                    @Override
 +                    protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
 +                        try {
 +                            if (StringUtils.isNotBlank(password.getModelObject())
 +                            && !password.getModelObject().equals(confirm.getModelObject())) {
 +                                throw new Exception(getString("passwordMismatch"));
 +                            }
 +
 +                            final BulkActionResult bulkActionResult;
 +                            switch (type) {
 +//                                case ASSIGN:
 +//                                    bulkActionResult = userRestClient.assign(
 +//                                            anyTO.getETagValue(),
 +//                                            anyTO.getKey(),
 +//                                            new ArrayList<>(selection),
 +//                                            changepwd.getModelObject(),
 +//                                            password.getModelObject());
 +//                                    break;
 +//                                case PROVISION:
 +//                                    bulkActionResult = userRestClient.provision(
 +//                                            anyTO.getETagValue(),
 +//                                            anyTO.getKey(),
 +//                                            new ArrayList<>(selection),
 +//                                            changepwd.getModelObject(),
 +//                                            password.getModelObject());
 +//                                    break;
 +                                default:
 +                                    bulkActionResult = null;
 +                                // ignore
 +                            }
 +
 +                            ((BasePage) pageRef.getPage()).setModalResult(true);
 +
 +                            if (bulkActionResult != null) {
 +                                loadBulkActionResultPage(selection, bulkActionResult);
 +                            } else {
 +
 +                                target.add(((BasePage) pageRef.getPage()).getFeedbackPanel());
 +                                window.close(target);
 +                            }
 +                        } catch (Exception e) {
 +                            LOG.error("Error provisioning resources", e);
 +                            error(getString(Constants.ERROR) + ": " + e.getMessage());
 +                            feedbackPanel.refresh(target);
 +                        }
 +                    }
 +                }.feedbackPanelAutomaticReload(false);
 +
 +        pwdMgtForm.addOrReplace(goon);
 +
 +        table.setVisible(false);
 +        pwdMgtForm.setVisible(true).setEnabled(true);
 +
 +        target.add(table);
 +        target.add(pwdMgt);
 +    }
 +
 +    private void loadBulkActionResultPage(
 +            final Collection<StatusBean> selection, final BulkActionResult bulkActionResult) {
 +        final List<String> resources = new ArrayList<String>(selection.size());
 +        for (StatusBean statusBean : selection) {
 +            resources.add(statusBean.getResourceName());
 +        }
 +
 +        final List<ConnObjectWrapper> connObjects =
 +                statusUtils.getConnectorObjects(Collections.singletonList(anyTO), resources);
 +
 +        final List<StatusBean> statusBeans = new ArrayList<StatusBean>(connObjects.size());
 +
 +        for (ConnObjectWrapper entry : connObjects) {
 +            final StatusBean statusBean = statusUtils.getStatusBean(anyTO,
 +                    entry.getResourceName(),
 +                    entry.getConnObjectTO(),
 +                    anyTO instanceof GroupTO);
 +
 +            statusBeans.add(statusBean);
 +        }
 +
 +        setResponsePage(new BulkActionResultModalPage<StatusBean, String>(
 +                window,
 +                statusBeans,
 +                columns,
 +                bulkActionResult,
 +                "resourceName"));
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
index a0a1ddc,0000000..89b856a
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
@@@ -1,186 -1,0 +1,186 @@@
 +/*
 + * 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.console.panels;
 +
 +import java.util.ArrayList;
 +import java.util.HashMap;
 +import java.util.Map;
 +import org.apache.syncope.client.console.rest.PolicyRestClient;
 +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
 +import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
 +import org.apache.syncope.common.lib.to.ResourceTO;
 +import org.apache.syncope.common.lib.types.PolicyType;
 +import org.apache.wicket.markup.html.WebMarkupContainer;
 +import org.apache.wicket.markup.html.form.ChoiceRenderer;
 +import org.apache.wicket.markup.html.form.DropDownChoice;
 +import org.apache.wicket.markup.html.panel.Panel;
 +import org.apache.wicket.model.IModel;
 +import org.apache.wicket.model.LoadableDetachableModel;
 +import org.apache.wicket.model.PropertyModel;
 +import org.apache.wicket.model.ResourceModel;
 +import org.apache.wicket.spring.injection.annot.SpringBean;
 +
 +public class ResourceSecurityPanel extends Panel {
 +
 +    private static final long serialVersionUID = -7982691107029848579L;
 +
 +    @SpringBean
 +    private PolicyRestClient policyRestClient;
 +
 +    private IModel<Map<Long, String>> passwordPolicies = null;
 +
 +    private IModel<Map<Long, String>> accountPolicies = null;
 +
 +    private IModel<Map<Long, String>> syncPolicies = null;
 +
 +    public ResourceSecurityPanel(final String id, final ResourceTO resourceTO) {
 +
 +        super(id);
 +
 +        setOutputMarkupId(true);
 +
 +        passwordPolicies = new LoadableDetachableModel<Map<Long, String>>() {
 +
 +            private static final long serialVersionUID = 5275935387613157437L;
 +
 +            @Override
 +            protected Map<Long, String> load() {
 +                Map<Long, String> res = new HashMap<>();
 +                for (AbstractPolicyTO policyTO : policyRestClient.getPolicies(PolicyType.PASSWORD)) {
 +                    res.put(policyTO.getKey(), policyTO.getDescription());
 +                }
 +                return res;
 +            }
 +        };
 +
 +        accountPolicies = new LoadableDetachableModel<Map<Long, String>>() {
 +
 +            private static final long serialVersionUID = -2012833443695917883L;
 +
 +            @Override
 +            protected Map<Long, String> load() {
 +                Map<Long, String> res = new HashMap<>();
 +                for (AbstractPolicyTO policyTO : policyRestClient.getPolicies(PolicyType.ACCOUNT)) {
 +                    res.put(policyTO.getKey(), policyTO.getDescription());
 +                }
 +                return res;
 +            }
 +        };
 +
 +        syncPolicies = new LoadableDetachableModel<Map<Long, String>>() {
 +
 +            private static final long serialVersionUID = -2012833443695917883L;
 +
 +            @Override
 +            protected Map<Long, String> load() {
 +                Map<Long, String> res = new HashMap<>();
 +                for (AbstractPolicyTO policyTO : policyRestClient.getPolicies(PolicyType.SYNC)) {
 +                    res.put(policyTO.getKey(), policyTO.getDescription());
 +                }
 +                return res;
 +            }
 +        };
 +
 +        final WebMarkupContainer securityContainer = new WebMarkupContainer("security");
 +
 +        securityContainer.setOutputMarkupId(true);
 +        add(securityContainer);
 +
 +        // -------------------------------
 +        // Password policy specification
 +        // -------------------------------
 +        final AjaxDropDownChoicePanel<Long> passwordPolicy = new AjaxDropDownChoicePanel<Long>("passwordPolicy",
 +                new ResourceModel("passwordPolicy", "passwordPolicy").getObject(), new PropertyModel<Long>(resourceTO,
 +                        "passwordPolicy"));
 +
 +        passwordPolicy.setChoiceRenderer(new PolicyRenderer(PolicyType.PASSWORD));
 +
 +        passwordPolicy.setChoices(new ArrayList<>(passwordPolicies.getObject().keySet()));
 +
 +        ((DropDownChoice<?>) passwordPolicy.getField()).setNullValid(true);
 +
 +        securityContainer.add(passwordPolicy);
 +        // -------------------------------
 +
 +        // -------------------------------
 +        // Account policy specification
 +        // -------------------------------
 +        final AjaxDropDownChoicePanel<Long> accountPolicy = new AjaxDropDownChoicePanel<Long>("accountPolicy",
 +                new ResourceModel("accountPolicy", "accountPolicy").getObject(), new PropertyModel<Long>(resourceTO,
 +                        "accountPolicy"));
 +
 +        accountPolicy.setChoiceRenderer(new PolicyRenderer(PolicyType.ACCOUNT));
 +
 +        accountPolicy.setChoices(new ArrayList<Long>(accountPolicies.getObject().keySet()));
 +
 +        ((DropDownChoice<?>) accountPolicy.getField()).setNullValid(true);
 +
 +        securityContainer.add(accountPolicy);
 +        // -------------------------------
 +
 +        // -------------------------------
 +        // Sync policy specification
 +        // -------------------------------
 +        final AjaxDropDownChoicePanel<Long> syncPolicy = new AjaxDropDownChoicePanel<Long>("syncPolicy",
 +                new ResourceModel("syncPolicy", "syncPolicy").getObject(), new PropertyModel<Long>(resourceTO,
 +                        "syncPolicy"));
 +
 +        syncPolicy.setChoiceRenderer(new PolicyRenderer(PolicyType.SYNC));
 +
 +        syncPolicy.setChoices(new ArrayList<Long>(syncPolicies.getObject().keySet()));
 +
 +        ((DropDownChoice<?>) syncPolicy.getField()).setNullValid(true);
 +
 +        securityContainer.add(syncPolicy);
 +        // -------------------------------
 +    }
 +
 +    private class PolicyRenderer extends ChoiceRenderer<Long> {
 +
 +        private static final long serialVersionUID = 8060500161321947000L;
 +
 +        private PolicyType type;
 +
-         public PolicyRenderer(final PolicyType type) {
++        PolicyRenderer(final PolicyType type) {
 +            super();
 +            this.type = type;
 +        }
 +
 +        @Override
 +        public Object getDisplayValue(final Long object) {
 +            switch (type) {
 +                case ACCOUNT:
 +                    return accountPolicies.getObject().get(object);
 +                case PASSWORD:
 +                    return passwordPolicies.getObject().get(object);
 +                case SYNC:
 +                    return syncPolicies.getObject().get(object);
 +                default:
 +                    return "";
 +            }
 +        }
 +
 +        @Override
 +        public String getIdValue(final Long object, final int index) {
 +            return String.valueOf(object != null
 +                    ? object
 +                    : 0L);
 +        }
 +    };
 +}


[24/54] [abbrv] syncope git commit: merge resolved

Posted by fm...@apache.org.
merge resolved


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

Branch: refs/heads/SYNCOPE-156
Commit: f8d46d3cf1570cd46ed3b2cac368ef32dfd542ae
Parents: 4739236 fc208d2
Author: massi <ma...@tirasa.net>
Authored: Tue Oct 20 14:56:40 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Tue Oct 20 14:56:40 2015 +0200

----------------------------------------------------------------------
 .../cli/commands/ConfigurationCommand.java      |   2 +-
 .../client/cli/commands/DomainCommand.java      |   2 +-
 .../client/cli/commands/HelpCommand.java        |   2 +-
 .../client/cli/commands/InfoCommand.java        |   2 +-
 .../client/cli/commands/LoggerCommand.java      | 271 +++++++++++++++++++
 .../cli/commands/NotificationCommand.java       |   2 +-
 .../client/cli/commands/PolicyCommand.java      |   2 +-
 .../client/cli/commands/ReportCommand.java      |   2 +-
 .../client/cli/commands/SchemaCommand.java      |   2 +-
 .../client/cli/commands/TaskCommand.java        |   2 +-
 .../cli/commands/install/InstallCommand.java    |   2 +-
 .../commons/SortableAnyProviderComparator.java  |   2 +-
 .../client/console/commons/status/Status.java   |   2 +-
 .../syncope/client/console/pages/Login.java     |   4 +-
 .../console/pages/ProvisioningModalPage.java    |   2 +-
 .../client/console/pages/StatusModalPage.java   |   2 +-
 .../console/panels/ResourceSecurityPanel.java   |   2 +-
 .../client/console/topology/Topology.java       |   2 +-
 .../console/topology/WebSocketBehavior.java     |   4 +-
 .../wicket/markup/html/form/ActionLink.java     |   2 +-
 .../provision/ProvisionWizardBuilder.java       |   6 +-
 .../client/lib/SyncopeClientFactoryBean.java    |   2 +-
 .../syncope/common/lib/types/AnyTypeKind.java   |   2 +-
 .../common/lib/types/ClientExceptionType.java   |   2 +-
 .../common/lib/types/IntMappingType.java        |   2 +-
 .../syncope/common/lib/types/TaskType.java      |   2 +-
 .../syncope/common/rest/api/Preference.java     |   2 +-
 .../syncope/core/logic/AbstractAnyLogic.java    |   2 +-
 .../syncope/core/logic/init/LoggerLoader.java   |   2 +-
 .../core/misc/jexl/ClassFreeUberspectImpl.java  |   2 +-
 .../persistence/api/ImplementationLookup.java   |   2 +-
 .../jpa/content/ContentLoaderHandler.java       |   2 +-
 .../jpa/content/MultiParentNode.java            |   2 +-
 .../core/persistence/jpa/dao/SearchSupport.java |   2 +-
 .../client/console/panels/CamelRoutePanel.java  |   2 +-
 .../syncope/installer/enums/Containers.java     |   2 +-
 .../org/apache/syncope/installer/enums/DBs.java |   2 +-
 pom.xml                                         |  14 +-
 38 files changed, 318 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/f8d46d3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/f8d46d3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/f8d46d3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/f8d46d3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/f8d46d3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
index 0000000,360c16b..4c6caf5
mode 000000,100644..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
@@@ -1,0 -1,267 +1,271 @@@
+ /*
+  * 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.cli.commands;
+ 
+ import java.util.ArrayList;
+ import java.util.List;
+ import javax.xml.ws.WebServiceException;
+ import org.apache.commons.lang3.StringUtils;
+ import org.apache.syncope.client.cli.Command;
+ import org.apache.syncope.client.cli.Input;
+ import org.apache.syncope.client.cli.SyncopeServices;
+ import org.apache.syncope.client.cli.messages.Messages;
++import org.apache.syncope.client.cli.util.CommandUtils;
+ import org.apache.syncope.common.lib.SyncopeClientException;
+ import org.apache.syncope.common.lib.to.LoggerTO;
+ import org.apache.syncope.common.lib.types.LoggerLevel;
+ import org.apache.syncope.common.lib.types.LoggerType;
+ import org.apache.syncope.common.rest.api.service.LoggerService;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ 
+ @Command(name = "logger")
+ public class LoggerCommand extends AbstractCommand {
+ 
+     private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
+ 
+     private static final String HELP_MESSAGE = "Usage: logger [options]\n"
+             + "  Options:\n"
+             + "    --help \n"
+             + "    --list \n"
+             + "    --read \n"
+             + "       Syntax: --read {LOG-NAME} {LOG-NAME} [...]\n"
+             + "    --update \n"
+             + "       Syntax: --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]\n"
+             + "    --update-all \n"
+             + "       Syntax: --update-all {LOG-LEVEL} \n"
+             + "    --create \n"
+             + "       Syntax: --create {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]\n"
+             + "    --delete \n"
+             + "       Syntax: --delete {LOG-NAME} {LOG-NAME} [...]";
+ 
+     @Override
+     public void execute(final Input input) {
+         LOG.debug("Option: {}", input.getOption());
+         LOG.debug("Parameters:");
+         for (final String parameter : input.getParameters()) {
+             LOG.debug("   > " + parameter);
+         }
+ 
+         final String[] parameters = input.getParameters();
+ 
+         if (StringUtils.isBlank(input.getOption())) {
+             input.setOption(Options.HELP.getOptionName());
+         }
+ 
+         final LoggerService loggerService = SyncopeServices.get(LoggerService.class);
+         switch (Options.fromName(input.getOption())) {
+             case LIST:
+                 try {
+                     for (final LoggerTO loggerTO : loggerService.list(LoggerType.LOG)) {
+                         System.out.println(" - " + loggerTO.getKey() + " -> " + loggerTO.getLevel());
+                         System.out.println("");
+                     }
+                 } catch (final SyncopeClientException ex) {
+                     Messages.printMessage("Error: " + ex.getMessage());
+                 }
+                 break;
+             case READ:
+                 final String readErrorMessage = "logger --read {LOG-NAME} {LOG-NAME} [...]";
+                 if (parameters.length >= 1) {
+                     for (final String parameter : parameters) {
+                         try {
+                             final LoggerTO loggerTO = loggerService.read(LoggerType.LOG, parameter);
+                             System.out.println("\n - Logger");
+                             System.out.println("   - key: " + loggerTO.getKey());
+                             System.out.println("   - level: " + loggerTO.getLevel());
+                             System.out.println("");
+                         } catch (final SyncopeClientException | WebServiceException ex) {
+                             if (ex.getMessage().startsWith("NotFound")) {
+                                 Messages.printNofFoundMessage("Logger", parameter);
+                             } else {
+                                 Messages.printMessage("Error: " + ex.getMessage());
+                             }
+                         }
+                     }
+                 } else {
+                     Messages.printCommandOptionMessage(readErrorMessage);
+                 }
+                 break;
+             case UPDATE:
+                 final String updateErrorMessage = "logger --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
+ 
+                 if (parameters.length >= 1) {
+                     Input.PairParameter pairParameter;
+                     for (final String parameter : parameters) {
+                         try {
+                             pairParameter = input.toPairParameter(parameter);
+                             final LoggerTO loggerTO = loggerService.read(LoggerType.LOG, pairParameter.getKey());
+                             loggerTO.setLevel(LoggerLevel.valueOf(pairParameter.getValue()));
+                             loggerService.update(LoggerType.LOG, loggerTO);
+                             System.out.
+                                     println("\n - Logger " + loggerTO.getKey() + " updated");
+                             System.out.println("   - new level: " + loggerTO.getLevel());
+                             System.out.println("");
+                         } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
+                             if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
+                                 Messages.printTypeNotValidMessage(
 -                                        "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
++                                        "logger level", input.firstParameter(),
++                                        CommandUtils.fromEnumToArray(LoggerLevel.class));
+                             } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
+                                 Messages.printMessage(ex.getMessage(), updateErrorMessage);
+                             } else if (ex.getMessage().startsWith("NotFound")) {
+                                 Messages.printNofFoundMessage("Logger", parameter);
+                             } else {
+                                 Messages.printMessage(ex.getMessage(), updateErrorMessage);
+                             }
+                             break;
+                         }
+                     }
+                 } else {
+                     Messages.printCommandOptionMessage(updateErrorMessage);
+                 }
+                 break;
+             case UPDATE_ALL:
+                 final String updateAllErrorMessage = "logger --update-all {LOG-LEVEL}";
+ 
+                 if (parameters.length == 1) {
+                     for (final LoggerTO loggerTO : loggerService.list(LoggerType.LOG)) {
+                         try {
+                             loggerTO.setLevel(LoggerLevel.valueOf(parameters[0]));
+                             loggerService.update(LoggerType.LOG, loggerTO);
+                             System.out.
+                                     println("\n - Logger " + loggerTO.getKey() + " updated");
+                             System.out.println("   - new level: " + loggerTO.getLevel());
+                             System.out.println("");
+                         } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
+                             if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
+                                 Messages.printTypeNotValidMessage(
 -                                        "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
++                                        "logger level", input.firstParameter(),
++                                        CommandUtils.fromEnumToArray(LoggerLevel.class));
+                             } else {
+                                 Messages.printMessage(ex.getMessage(), updateAllErrorMessage);
+                             }
+                             break;
+                         }
+                     }
+                 } else {
+                     Messages.printCommandOptionMessage(updateAllErrorMessage);
+                 }
+                 break;
+             case CREATE:
+                 final String createErrorMessage = "logger --create {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
+ 
+                 if (parameters.length >= 1) {
+                     Input.PairParameter pairParameter;
+                     LoggerTO loggerTO;
+                     for (final String parameter : parameters) {
+                         loggerTO = new LoggerTO();
+                         try {
+                             pairParameter = input.toPairParameter(parameter);
+                             loggerTO.setKey(pairParameter.getKey());
+                             loggerTO.setLevel(LoggerLevel.valueOf(pairParameter.getValue()));
+                             loggerService.update(LoggerType.LOG, loggerTO);
+                             System.out.
+                                     println("\n - Logger " + loggerTO.getKey() + " updated");
+                             System.out.println("   - level: " + loggerTO.getLevel());
+                             System.out.println("");
+                         } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
+                             Messages.printTypeNotValidMessage(
 -                                    "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
++                                    "logger level", input.firstParameter(),
++                                    CommandUtils.fromEnumToArray(LoggerLevel.class));
+                             break;
+                         }
+                     }
+                 } else {
+                     Messages.printCommandOptionMessage(createErrorMessage);
+                 }
+                 break;
+             case DELETE:
+                 final String deleteErrorMessage = "logger --delete {LOG-NAME} {LOG-NAME} [...]";
+ 
+                 if (parameters.length >= 1) {
+                     for (final String parameter : parameters) {
+                         try {
+                             loggerService.delete(LoggerType.LOG, parameter);
+                             Messages.printDeletedMessage("Logger", parameter);
+                         } catch (final WebServiceException | SyncopeClientException ex) {
+                             if (ex.getMessage().startsWith("NotFound")) {
+                                 Messages.printNofFoundMessage("Logger", parameter);
+                             } else {
+                                 Messages.printMessage(ex.getMessage());
+                             }
+                         }
+                     }
+                 } else {
+                     Messages.printCommandOptionMessage(deleteErrorMessage);
+                 }
+                 break;
+             case HELP:
+                 System.out.println(HELP_MESSAGE);
+                 break;
+             default:
+                 Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
+         }
+     }
+ 
+     @Override
+     public String getHelpMessage() {
+         return HELP_MESSAGE;
+     }
+ 
+     private enum Options {
+ 
+         HELP("--help"),
+         LIST("--list"),
+         READ("--read"),
+         UPDATE("--update"),
+         UPDATE_ALL("--update-all"),
+         CREATE("--create"),
+         DELETE("--delete");
+ 
+         private final String optionName;
+ 
+         Options(final String optionName) {
+             this.optionName = optionName;
+         }
+ 
+         public String getOptionName() {
+             return optionName;
+         }
+ 
+         public boolean equalsOptionName(final String otherName) {
+             return (otherName == null) ? false : optionName.equals(otherName);
+         }
+ 
+         public static Options fromName(final String name) {
+             Options optionToReturn = HELP;
+             for (final Options option : Options.values()) {
+                 if (option.equalsOptionName(name)) {
+                     optionToReturn = option;
+                 }
+             }
+             return optionToReturn;
+         }
+ 
+         public static List<String> toList() {
+             final List<String> options = new ArrayList<>();
+             for (final Options value : values()) {
+                 options.add(value.getOptionName());
+             }
+             return options;
+         }
+     }
+ 
+ }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f8d46d3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/f8d46d3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/f8d46d3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/f8d46d3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/f8d46d3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
----------------------------------------------------------------------


[13/54] [abbrv] syncope git commit: Merge branch '1_2_X'

Posted by fm...@apache.org.
Merge branch '1_2_X'


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

Branch: refs/heads/SYNCOPE-156
Commit: 6f4082cd7e324c87b076dc5eeefa11085b75d574
Parents: 2a99db9 03c9bc2
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Mon Oct 19 09:57:15 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Mon Oct 19 09:57:15 2015 +0200

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/6f4082cd/pom.xml
----------------------------------------------------------------------


[22/54] [abbrv] syncope git commit: introduced table view to print results (logger stack), SYNCOPE-158

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/messages/TwoColumnTable.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/TwoColumnTable.java b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/TwoColumnTable.java
new file mode 100644
index 0000000..df5bbea
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/TwoColumnTable.java
@@ -0,0 +1,262 @@
+
+/*
+ * 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.cli.messages;
+
+import java.util.Map;
+
+public class TwoColumnTable {
+
+    private static final int TABLE_BORDER = 1;
+
+    private static final int MIN_COLUMN_SPACE = 2;
+
+    private static final int MIN_COLUMN_SIZE = 5;
+
+    private int tableWidth;
+
+    private int firstColumntContentWidth;
+
+    private int secondColumntContentWidth;
+
+    private final String title;
+
+    private final String firstColumnHeader;
+
+    private int firstColumnMaxWidth;
+
+    private final String secondColumnHeader;
+
+    private int secondColumnMaxWidth;
+
+    public TwoColumnTable(final String title,
+            final String firstColumnHeader,
+            final int firstColumnMaxWidth,
+            final String secondColumnHeader,
+            final int secondColumnMaxWidth) {
+
+        this.firstColumnHeader = firstColumnHeader.toUpperCase();
+
+        if (firstColumnMaxWidth < MIN_COLUMN_SIZE) {
+            this.firstColumnMaxWidth = MIN_COLUMN_SIZE;
+        } else {
+            this.firstColumnMaxWidth = firstColumnMaxWidth;
+        }
+
+        this.secondColumnHeader = secondColumnHeader.toUpperCase();
+
+        if (secondColumnMaxWidth < MIN_COLUMN_SIZE) {
+            this.secondColumnMaxWidth = MIN_COLUMN_SIZE;
+        } else {
+            this.secondColumnMaxWidth = secondColumnMaxWidth;
+        }
+
+        tableWidth = (TABLE_BORDER * 3) + (MIN_COLUMN_SPACE * 4) + firstColumnMaxWidth + secondColumnMaxWidth;
+
+        if (title.length() > firstColumnMaxWidth + secondColumnMaxWidth) {
+            tableWidth = (TABLE_BORDER * 3) + (MIN_COLUMN_SPACE * 4) + title.length();
+        }
+
+        firstColumntContentWidth = (MIN_COLUMN_SPACE * 2) + firstColumnMaxWidth;
+        secondColumntContentWidth = (MIN_COLUMN_SPACE * 2) + secondColumnMaxWidth;
+
+        this.title = title.toUpperCase();
+    }
+
+    public void printTable(final Map<String, String> value) {
+
+        if (value.isEmpty()) {
+            firstColumnMaxWidth = firstColumnHeader.length();
+            secondColumnMaxWidth = secondColumnHeader.length();
+            firstColumntContentWidth = (MIN_COLUMN_SPACE * 2) + firstColumnMaxWidth;
+            secondColumntContentWidth = (MIN_COLUMN_SPACE * 2) + secondColumnMaxWidth;
+            tableWidth = (TABLE_BORDER * 3) + (MIN_COLUMN_SPACE * 4) + firstColumnMaxWidth + secondColumnMaxWidth;
+            if (title.length() > firstColumnMaxWidth + secondColumnMaxWidth) {
+                tableWidth = (TABLE_BORDER * 3) + (MIN_COLUMN_SPACE * 4) + title.length();
+            }
+        }
+
+        final StringBuilder table = new StringBuilder();
+
+// ################ BORDER-TOP ################
+        for (int i = 0; i < tableWidth; i++) {
+            table.append("#");
+        }
+        table.append("\n");
+// ################ BORDER-TOP ################
+
+// ################ TABLE-TITLE ################
+        table.append("#");
+        for (int i = 0; i < titleFirstSpace(title); i++) {
+            table.append(" ");
+        }
+        table.append(title);
+        for (int i = 0; i < titleSecondSpace(title); i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        table.append("\n");
+// ################ TABLE-TITLE ################
+
+// ################ BORDER-TOP ################
+        for (int i = 0; i < tableWidth; i++) {
+            table.append("#");
+        }
+        table.append("\n");
+// ################ BORDER-TOP ################
+
+// ################ LIST-SPACE ################
+        table.append("#");
+        for (int i = 0; i < firstColumntContentWidth; i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        for (int i = 0; i < secondColumntContentWidth; i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        table.append("\n");
+// ################ LIST-SPACE ################
+
+// ################ HEADER-TITLE ################
+        table.append("#");
+        for (int i = 0; i < firstColumnFirstSpace(firstColumnHeader); i++) {
+            table.append(" ");
+        }
+        table.append(firstColumnHeader);
+        for (int i = 0; i < firstColumnSecondSpace(firstColumnHeader); i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        for (int i = 0; i < secondColumnFirstSpace(secondColumnHeader); i++) {
+            table.append(" ");
+        }
+        table.append(secondColumnHeader);
+        for (int i = 0; i < secondColumnSecondSpace(secondColumnHeader); i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        table.append("\n");
+// ################ HEADER-TITLE ################
+
+// ################ LIST-SPACE ################
+        table.append("#");
+        for (int i = 0; i < firstColumntContentWidth; i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        for (int i = 0; i < secondColumntContentWidth; i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        table.append("\n");
+// ################ LIST-SPACE ################
+
+// ################ BORDER-TOP ################
+        for (int i = 0; i < tableWidth; i++) {
+            table.append("#");
+        }
+        table.append("\n");
+// ################ BORDER-TOP ################
+
+// ################ LIST-SPACE ################
+        table.append("#");
+        for (int i = 0; i < firstColumntContentWidth; i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        for (int i = 0; i < secondColumntContentWidth; i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        table.append("\n");
+// ################ LIST-SPACE ################
+
+// ################ CONTENT ################
+        for (final Map.Entry<String, String> entrySet : value.entrySet()) {
+            final String firstColumnValue = entrySet.getKey();
+            final String secondColumnValue = entrySet.getValue();
+            table.append("#");
+            for (int i = 0; i < firstColumnFirstSpace(firstColumnValue); i++) {
+                table.append(" ");
+            }
+            table.append(firstColumnValue);
+            for (int i = 0; i < firstColumnSecondSpace(firstColumnValue); i++) {
+                table.append(" ");
+            }
+            table.append("#");
+            for (int i = 0; i < secondColumnFirstSpace(secondColumnValue); i++) {
+                table.append(" ");
+            }
+            table.append(secondColumnValue);
+            for (int i = 0; i < secondColumnSecondSpace(secondColumnValue); i++) {
+                table.append(" ");
+            }
+            table.append("#");
+            table.append("\n");
+        }
+// ################ CONTENT ################
+
+// ################ LIST-SPACE ################
+        table.append("#");
+        for (int i = 0; i < firstColumntContentWidth; i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        for (int i = 0; i < secondColumntContentWidth; i++) {
+            table.append(" ");
+        }
+        table.append("#");
+        table.append("\n");
+// ################ LIST-SPACE ################
+
+// ################ BORDER-BOTTOM ################
+        for (int i = 0; i < tableWidth; i++) {
+            table.append("#");
+        }
+// ################ BORDER-BOTTOM ################
+
+        System.out.println(table.toString() + "\n");
+    }
+
+    private int titleFirstSpace(final String wordToPrint) {
+        return ((tableWidth - 2) - (wordToPrint.length())) / 2;
+    }
+
+    private int titleSecondSpace(final String wordToPrint) {
+        return tableWidth - 2 - (titleFirstSpace(wordToPrint) + wordToPrint.length());
+    }
+
+    private int firstColumnFirstSpace(final String wordToPrint) {
+        return (MIN_COLUMN_SPACE * 2 + (firstColumnMaxWidth - wordToPrint.length())) / 2;
+    }
+
+    private int firstColumnSecondSpace(final String wordToPrint) {
+        return firstColumntContentWidth - (firstColumnFirstSpace(wordToPrint) + wordToPrint.length());
+    }
+
+    private int secondColumnFirstSpace(final String wordToPrint) {
+        return (MIN_COLUMN_SPACE * 2 + (secondColumnMaxWidth - wordToPrint.length())) / 2;
+    }
+
+    private int secondColumnSecondSpace(final String wordToPrint) {
+        return secondColumntContentWidth - (secondColumnFirstSpace(wordToPrint) + wordToPrint.length());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/util/CommandUtils.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/util/CommandUtils.java b/client/cli/src/main/java/org/apache/syncope/client/cli/util/CommandUtils.java
index 2007743..b759877 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/util/CommandUtils.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/util/CommandUtils.java
@@ -55,7 +55,7 @@ public final class CommandUtils {
         final CommandClassScanner ccs = new CommandClassScanner();
         final List<Class<? extends AbstractCommand>> commands = ccs.getComponentClasses();
 
-        Class<? extends AbstractCommand> commandClass = null;
+        Class<? extends AbstractCommand> commandClass;
         for (final Class<? extends AbstractCommand> cmd : commands) {
             commandClass = cmd;
             if (commandClass == null) {
@@ -67,6 +67,24 @@ public final class CommandUtils {
         return listCommands;
     }
 
+    public static String[] fromEnumToArray(final Class<? extends Enum<?>> enumClass) {
+        final String[] types = new String[enumClass.getFields().length];
+        for (int i = 0; i < enumClass.getFields().length; i++) {
+            types[i] = enumClass.getFields()[i].getName();
+
+        }
+        return types;
+    }
+    
+    public static String helpMessage(final String command, final List<String> options) {
+        final StringBuilder helpMessageBuilder = new StringBuilder(String.format("Usage: %s [options]\n", command));
+        helpMessageBuilder.append("  Options:\n");
+        for (final String option : options) {
+            helpMessageBuilder.append("    ").append(option).append("\n");
+        }
+        return helpMessageBuilder.toString();
+    }
+
     private CommandUtils() {
 
     }


[11/54] [abbrv] syncope git commit: Fixed SYNCOPE-592, messages improvement SYNCOPE-158

Posted by fm...@apache.org.
Fixed SYNCOPE-592, messages improvement SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 2a99db9ce64bd9461fad9e1ac89bed7830b957dc
Parents: 405f212
Author: massi <ma...@tirasa.net>
Authored: Thu Oct 15 17:27:41 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Thu Oct 15 17:27:41 2015 +0200

----------------------------------------------------------------------
 .../apache/syncope/client/cli/SyncopeAdm.java   |  38 +-
 .../client/cli/commands/AbstractCommand.java    |   9 +
 .../cli/commands/ConfigurationCommand.java      |   4 +-
 .../client/cli/commands/DomainCommand.java      |   4 +-
 .../client/cli/commands/HelpCommand.java        |   4 +-
 .../client/cli/commands/InfoCommand.java        |   4 +-
 .../client/cli/commands/LoggerCommand.java      |  34 +-
 .../cli/commands/NotificationCommand.java       |   9 +-
 .../client/cli/commands/PolicyCommand.java      |  18 +-
 .../client/cli/commands/ReportCommand.java      |  42 +-
 .../client/cli/commands/SchemaCommand.java      |  30 +-
 .../client/cli/commands/TaskCommand.java        | 583 +++++++++++++++++++
 .../syncope/client/cli/messages/Messages.java   |  30 +
 .../syncope/common/lib/types/TaskType.java      |   2 +-
 14 files changed, 690 insertions(+), 121 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
index 3a66baa..d503498 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
@@ -20,6 +20,7 @@ package org.apache.syncope.client.cli;
 
 import org.apache.syncope.client.cli.commands.AbstractCommand;
 import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.util.CommandUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -27,20 +28,6 @@ public final class SyncopeAdm {
 
     private static final Logger LOG = LoggerFactory.getLogger(SyncopeAdm.class);
 
-    private static final String HELP_MESSAGE = "Usage: Main [options]\n"
-            + "  Options:\n"
-            + "    logger --help \n"
-            + "    config --help \n"
-            + "    notification --help \n"
-            + "    report --help \n"
-            + "    policy --help \n"
-            + "    entitlement --help \n"
-            + "    schema --help \n"
-            + "    install --help \n"
-            + "    info --help\n"
-            + "    domain --help\n"
-            + "    help\n";
-
     public static void main(final String[] args) {
         LOG.debug("Starting with args \n");
 
@@ -50,15 +37,34 @@ public final class SyncopeAdm {
             final AbstractCommand command = input.getCommand();
             command.execute(input);
         } catch (final IllegalAccessException | InstantiationException e) {
-            System.out.println(HELP_MESSAGE);
+            System.out.println(helpMessage());
         } catch (final IllegalArgumentException ex) {
             LOG.error("Error in main", ex);
             Messages.printMessage(ex.getMessage());
             if (!ex.getMessage().startsWith("It seems you")) {
-                System.out.println(HELP_MESSAGE);
+                System.out.println(helpMessage());
+            }
+        }
+
+    }
+
+    private static String helpMessage() {
+        final StringBuilder helpMessageBuilder = new StringBuilder("Usage: Main [options]\n");
+        helpMessageBuilder.append("  Options:\n");
+        try {
+            for (AbstractCommand command : CommandUtils.commands()) {
+                final String commandName = command.getClass().getAnnotation(Command.class).name();
+                helpMessageBuilder.append("    ").append(commandName);
+                if (!"help".equalsIgnoreCase(commandName)) {
+                    helpMessageBuilder.append(" --help");
+                }
+                helpMessageBuilder.append("\n");
             }
+        } catch (final IllegalAccessException | IllegalArgumentException | InstantiationException ex) {
+            Messages.printMessage(ex.getMessage());
         }
 
+        return helpMessageBuilder.toString();
     }
 
     private SyncopeAdm() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/AbstractCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/AbstractCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/AbstractCommand.java
index 7f272fe..7cee202 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/AbstractCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/AbstractCommand.java
@@ -35,4 +35,13 @@ public abstract class AbstractCommand {
     }
 
     public abstract String getHelpMessage();
+
+    protected static String[] fromEnumToArray(final Class<? extends Enum<?>> enumClass) {
+        final String[] types = new String[enumClass.getFields().length];
+        for (int i = 0; i < enumClass.getFields().length; i++) {
+            types[i] = enumClass.getFields()[i].getName();
+
+        }
+        return types;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
index 4b082ee..ee225d7 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
@@ -264,9 +264,7 @@ public class ConfigurationCommand extends AbstractCommand {
                 System.out.println(HELP_MESSAGE);
                 break;
             default:
-                System.out.println(input.getOption() + " is not a valid option.");
-                System.out.println("");
-                System.out.println(HELP_MESSAGE);
+                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
                 break;
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
index e733156..a2a0977 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
@@ -112,9 +112,7 @@ public class DomainCommand extends AbstractCommand {
                 System.out.println(HELP_MESSAGE);
                 break;
             default:
-                System.out.println(input.getOption() + " is not a valid option.");
-                System.out.println("");
-                System.out.println(HELP_MESSAGE);
+                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
         }
 
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
index c4008eb..85b7d73 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
@@ -63,9 +63,7 @@ public class HelpCommand extends AbstractCommand {
                 }
                 break;
             default:
-                System.out.println(input.getOption() + " is not a valid option.");
-                System.out.println("");
-                System.out.println(helpMessage("help", Options.toList()));
+                Messages.printDefaultMessage(input.getOption(), helpMessage("info", Options.toList()));
                 break;
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
index e6e1378..07bb952 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
@@ -267,9 +267,7 @@ public class InfoCommand extends AbstractCommand {
                 System.out.println(helpMessage("info", Options.toList()));
                 break;
             default:
-                System.out.println(input.getOption() + " is not a valid option.");
-                System.out.println("");
-                System.out.println(helpMessage("info", Options.toList()));
+                Messages.printDefaultMessage(input.getOption(), helpMessage("info", Options.toList()));
                 break;
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
index 6a5cde6..6c11c6f 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
@@ -106,7 +106,7 @@ public class LoggerCommand extends AbstractCommand {
                 final String updateErrorMessage = "logger --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
 
                 if (parameters.length >= 1) {
-                    Input.PairParameter pairParameter = null;
+                    Input.PairParameter pairParameter;
                     for (final String parameter : parameters) {
                         try {
                             pairParameter = input.toPairParameter(parameter);
@@ -119,12 +119,8 @@ public class LoggerCommand extends AbstractCommand {
                             System.out.println("");
                         } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
                             if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                                Messages.printMessage(ex.getMessage());
-                                System.out.println("Try with:");
-                                for (final LoggerLevel level : LoggerLevel.values()) {
-                                    System.out.println("  *** " + level.name());
-                                }
-                                System.out.println("");
+                                Messages.printTypeNotValidMessage(
+                                        "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
                             } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
                                 Messages.printMessage(ex.getMessage(), updateErrorMessage);
                             } else if (ex.getMessage().startsWith("NotFound")) {
@@ -153,12 +149,8 @@ public class LoggerCommand extends AbstractCommand {
                             System.out.println("");
                         } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
                             if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                                Messages.printMessage(ex.getMessage());
-                                System.out.println("Try with:");
-                                for (final LoggerLevel level : LoggerLevel.values()) {
-                                    System.out.println("  *** " + level.name());
-                                }
-                                System.out.println("");
+                                Messages.printTypeNotValidMessage(
+                                        "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
                             } else {
                                 Messages.printMessage(ex.getMessage(), updateAllErrorMessage);
                             }
@@ -187,16 +179,8 @@ public class LoggerCommand extends AbstractCommand {
                             System.out.println("   - level: " + loggerTO.getLevel());
                             System.out.println("");
                         } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
-                            if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                                Messages.printMessage(ex.getMessage());
-                                System.out.println("Try with:");
-                                for (final LoggerLevel level : LoggerLevel.values()) {
-                                    System.out.println("  *** " + level.name());
-                                }
-                                System.out.println("");
-                            } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
-                                Messages.printMessage(ex.getMessage(), createErrorMessage);
-                            }
+                            Messages.printTypeNotValidMessage(
+                                    "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
                             break;
                         }
                     }
@@ -228,9 +212,7 @@ public class LoggerCommand extends AbstractCommand {
                 System.out.println(HELP_MESSAGE);
                 break;
             default:
-                System.out.println(input.getOption() + " is not a valid option.");
-                System.out.println("");
-                System.out.println(HELP_MESSAGE);
+                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
index 49cc2e2..194ee11 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
@@ -78,7 +78,7 @@ public class NotificationCommand extends AbstractCommand {
                         try {
                             System.out.println(notificationService.read(Long.valueOf(parameter)));
                         } catch (final NumberFormatException ex) {
-                            System.out.println("Error reading " + parameter + ". It isn't a valid notification id");
+                            Messages.printIdNotNumberDeletedMessage("notification", parameter);
                         } catch (final WebServiceException | SyncopeClientException ex) {
                             if (ex.getMessage().startsWith("NotFound")) {
                                 Messages.printNofFoundMessage("Notification", parameter);
@@ -106,8 +106,7 @@ public class NotificationCommand extends AbstractCommand {
                                 Messages.printMessage(ex.getMessage());
                             }
                         } catch (final NumberFormatException ex) {
-                            Messages.printMessage(
-                                    "Error reading " + parameter + ". It isn't a valid notification id");
+                            Messages.printIdNotNumberDeletedMessage("notification", parameter);
                         }
                     }
                 } else {
@@ -118,9 +117,7 @@ public class NotificationCommand extends AbstractCommand {
                 System.out.println(HELP_MESSAGE);
                 break;
             default:
-                System.out.println(input.getOption() + " is not a valid option.");
-                System.out.println("");
-                System.out.println(HELP_MESSAGE);
+                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
index cd043ce..a69be18 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
@@ -77,12 +77,8 @@ public class PolicyCommand extends AbstractCommand {
                     } catch (final SyncopeClientException ex) {
                         Messages.printMessage(ex.getMessage());
                     } catch (final IllegalArgumentException ex) {
-                        Messages.printMessage(
-                                "Error: " + parameters[0] + " isn't a valid policy type, try with:");
-                        for (final PolicyType type : PolicyType.values()) {
-                            System.out.println("  *** " + type.name());
-                        }
-                        System.out.println("");
+                        Messages.printTypeNotValidMessage(
+                                "policy", input.firstParameter(), fromEnumToArray(PolicyType.class));
                     }
                 } else {
                     Messages.printCommandOptionMessage(listPolicyErrorMessage);
@@ -96,8 +92,7 @@ public class PolicyCommand extends AbstractCommand {
                         try {
                             System.out.println(policyService.read(Long.valueOf(parameter)));
                         } catch (final NumberFormatException ex) {
-                            Messages.printMessage(
-                                    "Error reading " + parameter + ". It isn't a valid policy id");
+                            Messages.printIdNotNumberDeletedMessage("policy", parameter);
                         } catch (final WebServiceException | SyncopeClientException ex) {
                             if (ex.getMessage().startsWith("NotFound")) {
                                 Messages.printNofFoundMessage("Policy", parameter);
@@ -128,8 +123,7 @@ public class PolicyCommand extends AbstractCommand {
                                 Messages.printMessage(ex.getMessage());
                             }
                         } catch (final NumberFormatException ex) {
-                            Messages.printMessage(
-                                    "Error reading " + parameter + ". It isn't a valid policy id");
+                            Messages.printIdNotNumberDeletedMessage("policy", parameter);
                         }
                     }
                 } else {
@@ -140,9 +134,7 @@ public class PolicyCommand extends AbstractCommand {
                 System.out.println(HELP_MESSAGE);
                 break;
             default:
-                System.out.println(input.getOption() + " is not a valid option.");
-                System.out.println("");
-                System.out.println(HELP_MESSAGE);
+                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
index 3d9770e..2178d22 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
@@ -109,14 +109,13 @@ public class ReportCommand extends AbstractCommand {
                 }
                 break;
             case READ:
-                final String readErrorMessage = "Usage: report --read {REPORT-ID} {REPORT-ID} [...]";
+                final String readErrorMessage = "report --read {REPORT-ID} {REPORT-ID} [...]";
                 if (parameters.length >= 1) {
                     for (final String parameter : parameters) {
                         try {
                             System.out.println(reportService.read(Long.valueOf(parameter)));
                         } catch (final NumberFormatException ex) {
-                            Messages.printMessage(
-                                    "Error reading " + parameter + ". It isn't a valid report id");
+                            Messages.printIdNotNumberDeletedMessage("report", parameter);
                         } catch (final WebServiceException | SyncopeClientException ex) {
                             if (ex.getMessage().startsWith("NotFound")) {
                                 Messages.printNofFoundMessage("Report", parameter);
@@ -130,9 +129,9 @@ public class ReportCommand extends AbstractCommand {
                 }
                 break;
             case DELETE:
-                final String deleteErrorMessage = "report --execute {REPORT-ID}";
+                final String deleteErrorMessage = "report --delete {REPORT-ID} {REPORT-ID} [...]";
 
-                if (parameters.length == 1) {
+                if (parameters.length >= 1) {
                     for (final String parameter : parameters) {
                         try {
                             reportService.delete(Long.valueOf(parameter));
@@ -146,8 +145,7 @@ public class ReportCommand extends AbstractCommand {
                                 Messages.printMessage(ex.getMessage());
                             }
                         } catch (final NumberFormatException ex) {
-                            Messages.printMessage(
-                                    "Error reading " + parameter + ". It isn't a valid report id");
+                            Messages.printIdNotNumberDeletedMessage("report", parameter);
                         }
                     }
                 } else {
@@ -155,7 +153,7 @@ public class ReportCommand extends AbstractCommand {
                 }
                 break;
             case EXECUTE:
-                final String executeErrorMessage = "Usage: report --execute {REPORT-ID}";
+                final String executeErrorMessage = "report --execute {REPORT-ID}";
 
                 if (parameters.length == 1) {
 
@@ -178,8 +176,7 @@ public class ReportCommand extends AbstractCommand {
                             Messages.printMessage(ex.getMessage());
                         }
                     } catch (final NumberFormatException ex) {
-                        Messages.printMessage(
-                                "Error reading " + parameters[0] + ". It isn't a valid report id");
+                        Messages.printIdNotNumberDeletedMessage("report", parameters[0]);
                     }
                 } else {
                     Messages.printCommandOptionMessage(executeErrorMessage);
@@ -205,8 +202,7 @@ public class ReportCommand extends AbstractCommand {
                                 Messages.printMessage(ex.getMessage());
                             }
                         } catch (final NumberFormatException ex) {
-                            Messages.printMessage(
-                                    "Error reading " + parameter + ". It isn't a valid report id");
+                            Messages.printIdNotNumberDeletedMessage("report", parameter);
                         }
                     }
                 } else {
@@ -232,7 +228,7 @@ public class ReportCommand extends AbstractCommand {
                                 System.out.println(ex.getMessage());
                             }
                         } catch (final NumberFormatException ex) {
-                            System.out.println("Error reading " + parameter + ". It isn't a valid report id");
+                            Messages.printIdNotNumberDeletedMessage("report", parameter);
                         }
                     }
                 } else {
@@ -241,7 +237,7 @@ public class ReportCommand extends AbstractCommand {
                 break;
             case EXPORT_EXECUTION_RESULT:
                 final String exportExecutionErrorMessage
-                        = "Usage: report --export-execution-result {EXECUTION-ID} {EXECUTION-ID} [...] {FORMAT}\n"
+                        = "report --export-execution-result {EXECUTION-ID} {EXECUTION-ID} [...] {FORMAT}\n"
                         + "          Format: CSV / HTML / PDF / XML / RTF";
 
                 if (parameters.length >= 2) {
@@ -281,19 +277,15 @@ public class ReportCommand extends AbstractCommand {
                                 System.out.println(ex.getMessage());
                             }
                         } catch (final NumberFormatException ex) {
-                            System.out.println("Error reading " + parameter + ". It isn't a valid report id");
+                            Messages.printIdNotNumberDeletedMessage("report", parameter);
                         } catch (IOException | ParserConfigurationException | SAXException | TransformerException e) {
                             System.out.println(" - Error creating " + "export_" + parameter + " " + e.getMessage());
                         } catch (final IllegalArgumentException ex) {
-                            if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                                System.out.println(" - Error: " + input.lastParameter()
-                                        + " isn't a valid policy type, try with:");
-                                for (final ReportExecExportFormat type : ReportExecExportFormat.values()) {
-                                    System.out.println("  *** " + type.name());
-                                }
-                            }
-                            break;
+                            Messages.printTypeNotValidMessage(
+                                    "format", input.firstParameter(),
+                                    fromEnumToArray(ReportExecExportFormat.class));
                         }
+                        break;
                     }
                 } else {
                     Messages.printCommandOptionMessage(exportExecutionErrorMessage);
@@ -303,9 +295,7 @@ public class ReportCommand extends AbstractCommand {
                 System.out.println(HELP_MESSAGE);
                 break;
             default:
-                System.out.println(input.getOption() + " is not a valid option.");
-                System.out.println("");
-                System.out.println(HELP_MESSAGE);
+                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
index 28e66de..7cb9ca1 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
@@ -18,6 +18,8 @@
  */
 package org.apache.syncope.client.cli.commands;
 
+import static org.apache.syncope.client.cli.commands.AbstractCommand.fromEnumToArray;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -98,12 +100,8 @@ public class SchemaCommand extends AbstractCommand {
                     } catch (final SyncopeClientException ex) {
                         Messages.printMessage(ex.getMessage());
                     } catch (final IllegalArgumentException ex) {
-                        Messages.printMessage(
-                                input.firstParameter() + " isn't a valid schema type, try with:");
-                        for (final SchemaType type : SchemaType.values()) {
-                            System.out.println("  *** " + type.name());
-                        }
-                        System.out.println("");
+                        Messages.printTypeNotValidMessage(
+                                "schema", input.firstParameter(), fromEnumToArray(SchemaType.class));
                     }
                 } else {
                     Messages.printCommandOptionMessage(listErrorMessage);
@@ -217,12 +215,8 @@ public class SchemaCommand extends AbstractCommand {
                             Messages.printMessage(ex.getMessage());
                         }
                     } catch (final IllegalArgumentException ex) {
-                        Messages.printMessage(
-                                parameters[0] + " isn't a valid schema type, try with:");
-                        for (final SchemaType type : SchemaType.values()) {
-                            System.out.println("  *** " + type.name());
-                        }
-                        System.out.println("");
+                        Messages.printTypeNotValidMessage(
+                                "schema", input.firstParameter(), fromEnumToArray(SchemaType.class));
                     }
                 } else {
                     Messages.printCommandOptionMessage(readErrorMessage);
@@ -248,12 +242,8 @@ public class SchemaCommand extends AbstractCommand {
                             Messages.printMessage(ex.getMessage());
                         }
                     } catch (final IllegalArgumentException ex) {
-                        Messages.printMessage(
-                                parameters[0] + " isn't a valid schema type, try with:");
-                        for (final SchemaType type : SchemaType.values()) {
-                            System.out.println("  *** " + type.name());
-                        }
-                        System.out.println("");
+                        Messages.printTypeNotValidMessage(
+                                "schema", input.firstParameter(), fromEnumToArray(SchemaType.class));
                     }
                 } else {
                     Messages.printCommandOptionMessage(deleteErrorMessage);
@@ -263,9 +253,7 @@ public class SchemaCommand extends AbstractCommand {
                 System.out.println(HELP_MESSAGE);
                 break;
             default:
-                System.out.println(input.getOption() + " is not a valid option.");
-                System.out.println("");
-                System.out.println(HELP_MESSAGE);
+                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
new file mode 100644
index 0000000..9dcb795
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
@@ -0,0 +1,583 @@
+/*
+ * 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.cli.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import javax.xml.ws.WebServiceException;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.NotificationTaskTO;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.to.SyncTaskTO;
+import org.apache.syncope.common.lib.to.TaskExecTO;
+import org.apache.syncope.common.lib.types.JobStatusType;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.common.rest.api.beans.TaskQuery;
+import org.apache.syncope.common.rest.api.service.TaskService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Command(name = "task")
+public class TaskCommand extends AbstractCommand {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
+
+    private static final String HELP_MESSAGE = "Usage: task [options]\n"
+            + "  Options:\n"
+            + "    --help \n"
+            + "    --list-task \n"
+            + "       Syntax: --list-task {TASK-TYPE} \n"
+            + "          Task type: NOTIFICATION / PROPAGATION / PUSH / SCHEDULED / SYNCHRONIZATION\n"
+            + "    --list-running-jobs \n"
+            + "    --list-scheduled-jobs \n"
+            + "    --read \n"
+            + "       Syntax: --read {TASK-ID} {TASK-ID} [...]\n"
+            + "    --read-execution \n"
+            + "       Syntax: --read-execution {TASK-EXEC-ID} {TASK-EXEC-ID} [...]\n"
+            + "    --delete \n"
+            + "       Syntax: --delete {TASK-ID} {TASK-ID} [...]\n"
+            + "    --delete-execution \n"
+            + "       Syntax: --delete-execution {TASK-EXEC-ID} {TASK-EXEC-ID} [...]\n"
+            + "    --execute \n"
+            + "       Syntax: --execute {TASK-ID} {DRY-RUN}"
+            + "          Dry run: true / false";
+
+    @Override
+    public void execute(final Input input) {
+        LOG.debug("Option: {}", input.getOption());
+        LOG.debug("Parameters:");
+        for (final String parameter : input.getParameters()) {
+            LOG.debug("   > " + parameter);
+        }
+
+        final String[] parameters = input.getParameters();
+
+        if (StringUtils.isBlank(input.getOption())) {
+            input.setOption(Options.HELP.getOptionName());
+        }
+
+        final TaskService taskService = SyncopeServices.get(TaskService.class);
+        switch (Options.fromName(input.getOption())) {
+            case LIST_TASK:
+                final String listTaskErrorMessage = "task --list-task {TASK-TYPE}\n"
+                        + "   Task type: NOTIFICATION / PROPAGATION / PUSH / SCHEDULED / SYNCHRONIZATION";
+                if (parameters.length == 1) {
+                    try {
+                        final TaskType taskType = TaskType.valueOf(parameters[0]);
+                        for (final AbstractTaskTO taskTO : taskService.list(taskType, new TaskQuery()).getResult()) {
+                            switch (taskType) {
+                                case NOTIFICATION:
+                                    final NotificationTaskTO notificationTaskTO = (NotificationTaskTO) taskTO;
+                                    System.out.println("");
+                                    System.out.println(" - Notification task key: " + notificationTaskTO.getKey());
+                                    System.out.println("     executed: " + notificationTaskTO.isExecuted());
+                                    System.out.println("     sender: " + notificationTaskTO.getSender());
+                                    System.out.println("     subjetc: " + notificationTaskTO.getSubject());
+                                    System.out.println("     text body: " + notificationTaskTO.getTextBody());
+                                    System.out.println("     html body: " + notificationTaskTO.getHtmlBody());
+                                    System.out.println("     latest execution status: "
+                                            + notificationTaskTO.getLatestExecStatus());
+                                    System.out.println("     start date: " + notificationTaskTO.getStartDate());
+                                    System.out.println("     end date: " + notificationTaskTO.getEndDate());
+                                    System.out.println("     recipients: " + notificationTaskTO.getRecipients());
+                                    System.out.println("     trace level: " + notificationTaskTO.getTraceLevel());
+                                    for (final TaskExecTO taskExecTO : notificationTaskTO.getExecutions()) {
+                                        printTaskExecTO(taskExecTO);
+                                    }
+                                    System.out.println("");
+                                    break;
+                                case PROPAGATION:
+                                    final PropagationTaskTO propagationTaskTO = (PropagationTaskTO) taskTO;
+                                    System.out.println("");
+                                    System.out.println(" - Propagation task key: " + propagationTaskTO.getKey());
+                                    System.out.println("     resource: " + propagationTaskTO.getResource());
+                                    System.out.println("     any key: " + propagationTaskTO.getAnyKey());
+                                    System.out.println("     any type kind: " + propagationTaskTO.getAnyTypeKind());
+                                    System.out.println("     connector object key: "
+                                            + propagationTaskTO.getConnObjectKey());
+                                    System.out.println("     old connector object key: "
+                                            + propagationTaskTO.getOldConnObjectKey());
+                                    System.out.println("     latest execution status: "
+                                            + propagationTaskTO.getLatestExecStatus());
+                                    System.out.println("     class name: " + propagationTaskTO.getObjectClassName());
+                                    System.out.println("     xml attribute: " + propagationTaskTO.getXmlAttributes());
+                                    System.out.println("     start date: " + propagationTaskTO.getStartDate());
+                                    System.out.println("     end date: " + propagationTaskTO.getEndDate());
+                                    System.out.println("     operation: " + propagationTaskTO.getOperation());
+                                    for (final TaskExecTO taskExecTO : propagationTaskTO.getExecutions()) {
+                                        printTaskExecTO(taskExecTO);
+                                    }
+                                    System.out.println("");
+                                    break;
+                                case PUSH:
+                                    final PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
+                                    System.out.println("");
+                                    System.out.println(" - Push task key: " + pushTaskTO.getKey());
+                                    System.out.println("     name: " + pushTaskTO.getName());
+                                    System.out.println("     resource: " + pushTaskTO.getResource());
+                                    System.out.println("     cron expression: " + pushTaskTO.getCronExpression());
+                                    System.out.println("     description: " + pushTaskTO.getDescription());
+                                    System.out.println("     is perform create: " + pushTaskTO.isPerformCreate());
+                                    System.out.println("     is perform delete: " + pushTaskTO.isPerformDelete());
+                                    System.out.println("     is perform update: " + pushTaskTO.isPerformUpdate());
+                                    System.out.println("     is sync status: " + pushTaskTO.isSyncStatus());
+                                    System.out.println("     start date: " + pushTaskTO.getStartDate());
+                                    System.out.println("     end date: " + pushTaskTO.getEndDate());
+                                    System.out.println("     last execution: " + pushTaskTO.getLastExec());
+                                    System.out.println("     next execution: " + pushTaskTO.getNextExec());
+                                    System.out.println("     latest execution status: "
+                                            + pushTaskTO.getLatestExecStatus());
+                                    System.out.println("     filters: " + pushTaskTO.getFilters());
+                                    System.out.println("     delegate class: " + pushTaskTO.getJobDelegateClassName());
+                                    System.out.println("     action class: " + pushTaskTO.getActionsClassNames());
+                                    System.out.println("     matching rule: " + pushTaskTO.getMatchingRule());
+                                    System.out.println("     not matching rule: " + pushTaskTO.getUnmatchingRule());
+                                    for (final TaskExecTO taskExecTO : pushTaskTO.getExecutions()) {
+                                        printTaskExecTO(taskExecTO);
+                                    }
+                                    System.out.println("");
+                                    break;
+                                case SCHEDULED:
+                                    final SchedTaskTO schedTaskTO = (SchedTaskTO) taskTO;
+                                    System.out.println("");
+                                    System.out.println(" - Scheduled task key: " + schedTaskTO.getKey());
+                                    System.out.println("     name: " + schedTaskTO.getName());
+                                    System.out.println("     cron expression: " + schedTaskTO.getCronExpression());
+                                    System.out.println("     description: " + schedTaskTO.getDescription());
+                                    System.out.println("     start date: " + schedTaskTO.getStartDate());
+                                    System.out.println("     end date: " + schedTaskTO.getEndDate());
+                                    System.out.println("     last execution: " + schedTaskTO.getLastExec());
+                                    System.out.println("     next execution: " + schedTaskTO.getNextExec());
+                                    System.out.println("     latest execution status: "
+                                            + schedTaskTO.getLatestExecStatus());
+                                    System.out.println("     job delegate class: "
+                                            + schedTaskTO.getJobDelegateClassName());
+                                    for (final TaskExecTO taskExecTO : schedTaskTO.getExecutions()) {
+                                        printTaskExecTO(taskExecTO);
+                                    }
+                                    System.out.println("");
+                                    break;
+                                case SYNCHRONIZATION:
+                                    final SyncTaskTO syncTaskTO = (SyncTaskTO) taskTO;
+                                    System.out.println("");
+                                    System.out.println(" - Sync task key: " + syncTaskTO.getKey());
+                                    System.out.println("     name: " + syncTaskTO.getName());
+                                    System.out.println("     resource: " + syncTaskTO.getResource());
+                                    System.out.println("     realm destination: " + syncTaskTO.getDestinationRealm());
+                                    System.out.println("     cron expression: " + syncTaskTO.getCronExpression());
+                                    System.out.println("     description: " + syncTaskTO.getDescription());
+                                    System.out.println("     is full reconciliation: "
+                                            + syncTaskTO.isFullReconciliation());
+                                    System.out.println("     is perform create: " + syncTaskTO.isPerformCreate());
+                                    System.out.println("     is perform delete: " + syncTaskTO.isPerformDelete());
+                                    System.out.println("     is perform update: " + syncTaskTO.isPerformUpdate());
+                                    System.out.println("     is sync status: " + syncTaskTO.isSyncStatus());
+                                    System.out.println("     templates:");
+                                    for (Map.Entry<String, AnyTO> entrySet : syncTaskTO.getTemplates().entrySet()) {
+                                        final String key = entrySet.getKey();
+                                        final AnyTO value = entrySet.getValue();
+                                        System.out.println("        " + key + " key: " + value.getKey()
+                                                + " of realm" + value.getRealm()
+                                                + " on resource " + value.getResources());
+
+                                    }
+                                    System.out.println("     start date: " + syncTaskTO.getStartDate());
+                                    System.out.println("     end date: " + syncTaskTO.getEndDate());
+                                    System.out.println("     next execution: " + syncTaskTO.getNextExec());
+                                    System.out.println("     last execution: " + syncTaskTO.getLastExec());
+                                    System.out.println("     latest execution status: "
+                                            + syncTaskTO.getLatestExecStatus());
+                                    System.out.println("     job delegate class: "
+                                            + syncTaskTO.getJobDelegateClassName());
+                                    System.out.println("     action class name: " + syncTaskTO.getActionsClassNames());
+                                    System.out.println("     matching rule: " + syncTaskTO.getMatchingRule());
+                                    System.out.println("     unmatching rule: " + syncTaskTO.getUnmatchingRule());
+                                    for (final TaskExecTO taskExecTO : syncTaskTO.getExecutions()) {
+                                        printTaskExecTO(taskExecTO);
+                                    }
+                                    System.out.println("");
+                                    break;
+                                default:
+                                    break;
+                            }
+                        }
+                    } catch (final SyncopeClientException ex) {
+                        Messages.printMessage(ex.getMessage());
+                    } catch (final IllegalArgumentException ex) {
+                        Messages.printTypeNotValidMessage("task", parameters[0], fromEnumToArray(TaskType.class));
+                    }
+                } else {
+                    Messages.printCommandOptionMessage(listTaskErrorMessage);
+                }
+                break;
+            case LIST_RUNNING_JOBS:
+                try {
+                    for (final TaskExecTO taskExecTO : taskService.listJobs(JobStatusType.RUNNING)) {
+                        printTaskExecTO(taskExecTO);
+                    }
+                } catch (final SyncopeClientException ex) {
+                    Messages.printMessage(ex.getMessage());
+                }
+                break;
+            case LIST_SCHEDULED_JOBS:
+                try {
+                    for (final TaskExecTO taskExecTO : taskService.listJobs(JobStatusType.SCHEDULED)) {
+                        printTaskExecTO(taskExecTO);
+                    }
+                } catch (final SyncopeClientException ex) {
+                    Messages.printMessage(ex.getMessage());
+                }
+                break;
+            case READ:
+                final String readErrorMessage = "task --read {TASK-ID} {TASK-ID} [...]";
+                if (parameters.length >= 1) {
+                    for (final String parameter : parameters) {
+                        try {
+                            final AbstractTaskTO taskTO = taskService.read(Long.valueOf(parameter));
+                            if (taskTO instanceof NotificationTaskTO) {
+                                final NotificationTaskTO notificationTaskTO = (NotificationTaskTO) taskTO;
+                                System.out.println("");
+                                System.out.println(" - Notification task key: " + notificationTaskTO.getKey());
+                                System.out.println("     executed: " + notificationTaskTO.isExecuted());
+                                System.out.println("     sender: " + notificationTaskTO.getSender());
+                                System.out.println("     subjetc: " + notificationTaskTO.getSubject());
+                                System.out.println("     text body: " + notificationTaskTO.getTextBody());
+                                System.out.println("     html body: " + notificationTaskTO.getHtmlBody());
+                                System.out.println("     latest execution status: "
+                                        + notificationTaskTO.getLatestExecStatus());
+                                System.out.println("     start date: " + notificationTaskTO.getStartDate());
+                                System.out.println("     end date: " + notificationTaskTO.getEndDate());
+                                System.out.println("     recipients: " + notificationTaskTO.getRecipients());
+                                System.out.println("     trace level: " + notificationTaskTO.getTraceLevel());
+                                for (final TaskExecTO taskExecTO : notificationTaskTO.getExecutions()) {
+                                    printTaskExecTO(taskExecTO);
+                                }
+                                System.out.println("");
+                            } else if (taskTO instanceof PropagationTaskTO) {
+                                final PropagationTaskTO propagationTaskTO = (PropagationTaskTO) taskTO;
+                                System.out.println("");
+                                System.out.println(" - Propagation task key: " + propagationTaskTO.getKey());
+                                System.out.println("     resource: " + propagationTaskTO.getResource());
+                                System.out.println("     any key: " + propagationTaskTO.getAnyKey());
+                                System.out.println("     any type kind: " + propagationTaskTO.getAnyTypeKind());
+                                System.out.println("     connector object key: "
+                                        + propagationTaskTO.getConnObjectKey());
+                                System.out.println("     old connector object key: "
+                                        + propagationTaskTO.getOldConnObjectKey());
+                                System.out.println("     latest execution status: "
+                                        + propagationTaskTO.getLatestExecStatus());
+                                System.out.println("     class name: " + propagationTaskTO.getObjectClassName());
+                                System.out.println("     xml attribute: " + propagationTaskTO.getXmlAttributes());
+                                System.out.println("     start date: " + propagationTaskTO.getStartDate());
+                                System.out.println("     end date: " + propagationTaskTO.getEndDate());
+                                System.out.println("     operation: " + propagationTaskTO.getOperation());
+                                for (final TaskExecTO taskExecTO : propagationTaskTO.getExecutions()) {
+                                    printTaskExecTO(taskExecTO);
+                                }
+                                System.out.println("");
+                            } else if (taskTO instanceof PushTaskTO) {
+                                final PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
+                                System.out.println("");
+                                System.out.println(" - Push task key: " + pushTaskTO.getKey());
+                                System.out.println("     name: " + pushTaskTO.getName());
+                                System.out.println("     resource: " + pushTaskTO.getResource());
+                                System.out.println("     cron expression: " + pushTaskTO.getCronExpression());
+                                System.out.println("     description: " + pushTaskTO.getDescription());
+                                System.out.println("     is perform create: " + pushTaskTO.isPerformCreate());
+                                System.out.println("     is perform delete: " + pushTaskTO.isPerformDelete());
+                                System.out.println("     is perform update: " + pushTaskTO.isPerformUpdate());
+                                System.out.println("     is sync status: " + pushTaskTO.isSyncStatus());
+                                System.out.println("     start date: " + pushTaskTO.getStartDate());
+                                System.out.println("     end date: " + pushTaskTO.getEndDate());
+                                System.out.println("     last execution: " + pushTaskTO.getLastExec());
+                                System.out.println("     next execution: " + pushTaskTO.getNextExec());
+                                System.out.println("     latest execution status: "
+                                        + pushTaskTO.getLatestExecStatus());
+                                System.out.println("     filters: " + pushTaskTO.getFilters());
+                                System.out.println("     delegate class: " + pushTaskTO.getJobDelegateClassName());
+                                System.out.println("     action class: " + pushTaskTO.getActionsClassNames());
+                                System.out.println("     matching rule: " + pushTaskTO.getMatchingRule());
+                                System.out.println("     not matching rule: " + pushTaskTO.getUnmatchingRule());
+                                for (final TaskExecTO taskExecTO : pushTaskTO.getExecutions()) {
+                                    printTaskExecTO(taskExecTO);
+                                }
+                                System.out.println("");
+                            } else if (taskTO instanceof SchedTaskTO) {
+                                final SchedTaskTO schedTaskTO = (SchedTaskTO) taskTO;
+                                System.out.println("");
+                                System.out.println(" - Scheduled task key: " + schedTaskTO.getKey());
+                                System.out.println("     name: " + schedTaskTO.getName());
+                                System.out.println("     cron expression: " + schedTaskTO.getCronExpression());
+                                System.out.println("     description: " + schedTaskTO.getDescription());
+                                System.out.println("     start date: " + schedTaskTO.getStartDate());
+                                System.out.println("     end date: " + schedTaskTO.getEndDate());
+                                System.out.println("     last execution: " + schedTaskTO.getLastExec());
+                                System.out.println("     next execution: " + schedTaskTO.getNextExec());
+                                System.out.println("     latest execution status: "
+                                        + schedTaskTO.getLatestExecStatus());
+                                System.out.println("     job delegate class: "
+                                        + schedTaskTO.getJobDelegateClassName());
+                                for (final TaskExecTO taskExecTO : schedTaskTO.getExecutions()) {
+                                    printTaskExecTO(taskExecTO);
+                                }
+                                System.out.println("");
+                            } else if (taskTO instanceof SyncTaskTO) {
+                                final SyncTaskTO syncTaskTO = (SyncTaskTO) taskTO;
+                                System.out.println("");
+                                System.out.println(" - Sync task key: " + syncTaskTO.getKey());
+                                System.out.println("     name: " + syncTaskTO.getName());
+                                System.out.println("     resource: " + syncTaskTO.getResource());
+                                System.out.println("     realm destination: " + syncTaskTO.getDestinationRealm());
+                                System.out.println("     cron expression: " + syncTaskTO.getCronExpression());
+                                System.out.println("     description: " + syncTaskTO.getDescription());
+                                System.out.println("     is full reconciliation: "
+                                        + syncTaskTO.isFullReconciliation());
+                                System.out.println("     is perform create: " + syncTaskTO.isPerformCreate());
+                                System.out.println("     is perform delete: " + syncTaskTO.isPerformDelete());
+                                System.out.println("     is perform update: " + syncTaskTO.isPerformUpdate());
+                                System.out.println("     is sync status: " + syncTaskTO.isSyncStatus());
+                                System.out.println("     templates:");
+                                for (Map.Entry<String, AnyTO> entrySet : syncTaskTO.getTemplates().entrySet()) {
+                                    final String key = entrySet.getKey();
+                                    final AnyTO value = entrySet.getValue();
+                                    System.out.println("        " + key + "key : " + value.getKey()
+                                            + " of realm" + value.getRealm()
+                                            + " on resource " + value.getResources());
+
+                                }
+                                System.out.println("     start date: " + syncTaskTO.getStartDate());
+                                System.out.println("     end date: " + syncTaskTO.getEndDate());
+                                System.out.println("     next execution: " + syncTaskTO.getNextExec());
+                                System.out.println("     last execution: " + syncTaskTO.getLastExec());
+                                System.out.println("     latest execution status: "
+                                        + syncTaskTO.getLatestExecStatus());
+                                System.out.println("     job delegate class: "
+                                        + syncTaskTO.getJobDelegateClassName());
+                                System.out.println("     action class name: " + syncTaskTO.getActionsClassNames());
+                                System.out.println("     matching rule: " + syncTaskTO.getMatchingRule());
+                                System.out.println("     unmatching rule: " + syncTaskTO.getUnmatchingRule());
+                                for (final TaskExecTO taskExecTO : syncTaskTO.getExecutions()) {
+                                    printTaskExecTO(taskExecTO);
+                                }
+                                System.out.println("");
+                            }
+                        } catch (final NumberFormatException ex) {
+                            Messages.printIdNotNumberDeletedMessage("task", parameter);
+                        } catch (final SyncopeClientException | WebServiceException ex) {
+                            if (ex.getMessage().startsWith("NotFound")) {
+                                Messages.printNofFoundMessage("Task", parameter);
+                            } else {
+                                Messages.printMessage("Error: " + ex.getMessage());
+                            }
+                            break;
+                        }
+                    }
+                } else {
+                    Messages.printCommandOptionMessage(readErrorMessage);
+                }
+                break;
+            case READ_EXECUTION:
+                final String readExecutionErrorMessage = "task --read-execution {TASK-ID} {TASK-ID} [...]";
+                if (parameters.length >= 1) {
+                    for (final String parameter : parameters) {
+                        try {
+                            final TaskExecTO taskExecTO = taskService.readExecution(Long.valueOf(parameter));
+                            printTaskExecTO(taskExecTO);
+                        } catch (final NumberFormatException ex) {
+                            Messages.printIdNotNumberDeletedMessage("task execution", parameter);
+                        } catch (final SyncopeClientException | WebServiceException ex) {
+                            if (ex.getMessage().startsWith("NotFound")) {
+                                Messages.printNofFoundMessage("Task execution", parameter);
+                            } else {
+                                Messages.printMessage("Error: " + ex.getMessage());
+                            }
+                            break;
+                        }
+                    }
+                } else {
+                    Messages.printCommandOptionMessage(readExecutionErrorMessage);
+                }
+                break;
+            case DELETE:
+                final String deleteErrorMessage = "task --delete {TASK-ID} {TASK-ID} [...]";
+
+                if (parameters.length >= 1) {
+                    for (final String parameter : parameters) {
+                        try {
+                            taskService.delete(Long.valueOf(parameter));
+                            Messages.printDeletedMessage("Task", parameter);
+                        } catch (final WebServiceException | SyncopeClientException ex) {
+                            if (ex.getMessage().startsWith("NotFound")) {
+                                Messages.printNofFoundMessage("Task", parameter);
+                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
+                                Messages.printMessage("You cannot delete task " + parameter);
+                            } else {
+                                Messages.printMessage(ex.getMessage());
+                            }
+                        } catch (final NumberFormatException ex) {
+                            Messages.printIdNotNumberDeletedMessage("task", parameter);
+                        }
+                    }
+                } else {
+                    Messages.printCommandOptionMessage(deleteErrorMessage);
+                }
+                break;
+            case DELETE_EXECUTION:
+                final String deleteExecutionErrorMessage = "task --delete-execution "
+                        + "{TASK-EXEC-ID} {TASK-EXEC-ID} [...]";
+
+                if (parameters.length >= 1) {
+                    for (final String parameter : parameters) {
+                        try {
+                            taskService.deleteExecution(Long.valueOf(parameter));
+                            Messages.printDeletedMessage("Task execution", parameter);
+                        } catch (final WebServiceException | SyncopeClientException ex) {
+                            if (ex.getMessage().startsWith("NotFound")) {
+                                Messages.printNofFoundMessage("Task execution", parameter);
+                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
+                                Messages.printMessage("You cannot delete task execution" + parameter);
+                            } else {
+                                Messages.printMessage(ex.getMessage());
+                            }
+                        } catch (final NumberFormatException ex) {
+                            Messages.printIdNotNumberDeletedMessage("task execution", parameter);
+                        }
+                    }
+                } else {
+                    Messages.printCommandOptionMessage(deleteExecutionErrorMessage);
+                }
+                break;
+            case EXECUTE:
+                final String executeErrorMessage = "task --execute {TASK-ID} {DRY-RUN}\n"
+                        + "          Dry run: true / false";
+
+                if (parameters.length == 2) {
+
+                    try {
+                        final Long taskIdToExecute = Long.valueOf(parameters[0]);
+                        boolean dryRun;
+                        if ("false".equalsIgnoreCase(parameters[1])) {
+                            dryRun = false;
+                        } else if ("true".equalsIgnoreCase(parameters[1])) {
+                            dryRun = true;
+                        } else {
+                            Messages.printNotBooleanDeletedMessage("dry run", parameters[1]);
+                            break;
+                        }
+                        final TaskExecTO taskExecTO = taskService.execute(taskIdToExecute, dryRun);
+                        printTaskExecTO(taskExecTO);
+                    } catch (final WebServiceException | SyncopeClientException ex) {
+                        System.out.println("Error:");
+                        if (ex.getMessage().startsWith("NotFound")) {
+                            Messages.printNofFoundMessage("Task", parameters[0]);
+                        } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
+                            Messages.printMessage("You cannot delete task " + parameters[0]);
+                        } else {
+                            Messages.printMessage(ex.getMessage());
+                        }
+                    } catch (final NumberFormatException ex) {
+                        Messages.printIdNotNumberDeletedMessage("task", parameters[0]);
+                    }
+                } else {
+                    Messages.printCommandOptionMessage(executeErrorMessage);
+                }
+                break;
+            case HELP:
+                System.out.println(HELP_MESSAGE);
+                break;
+            default:
+                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
+        }
+
+    }
+
+    private void printTaskExecTO(final TaskExecTO taskExecTO) {
+        System.out.println("     EXECUTIONS: ");
+        System.out.println("     - task execution key: " + taskExecTO.getKey());
+        System.out.println("       task: " + taskExecTO.getTask());
+        System.out.println("       message: ");
+        System.out.println("       ###############     <BEGIN MESSAGE>     ###############");
+        System.out.println("       message: " + taskExecTO.getMessage());
+        System.out.println("       ###############     <END   MESSAGE>     ###############");
+        System.out.println("       status: " + taskExecTO.getStatus());
+        System.out.println("       start date: " + taskExecTO.getStartDate());
+        System.out.println("       end date: " + taskExecTO.getEndDate());
+        System.out.println("");
+    }
+
+    @Override
+    public String getHelpMessage() {
+        return HELP_MESSAGE;
+    }
+
+    private enum Options {
+
+        HELP("--help"),
+        LIST_TASK("--list-task"),
+        LIST_RUNNING_JOBS("--list-running-jobs"),
+        LIST_SCHEDULED_JOBS("--list-scheduled-jobs"),
+        READ("--read"),
+        READ_EXECUTION("--read-execution"),
+        DELETE("--delete"),
+        DELETE_EXECUTION("--delete-execution"),
+        EXECUTE("--execute");
+
+        private final String optionName;
+
+        private Options(final String optionName) {
+            this.optionName = optionName;
+        }
+
+        public String getOptionName() {
+            return optionName;
+        }
+
+        public boolean equalsOptionName(final String otherName) {
+            return (otherName == null) ? false : optionName.equals(otherName);
+        }
+
+        public static Options fromName(final String name) {
+            Options optionToReturn = HELP;
+            for (final Options option : Options.values()) {
+                if (option.equalsOptionName(name)) {
+                    optionToReturn = option;
+                }
+            }
+            return optionToReturn;
+        }
+
+        public static List<String> toList() {
+            final List<String> options = new ArrayList<>();
+            for (final Options value : values()) {
+                options.add(value.getOptionName());
+            }
+            return options;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Messages.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Messages.java b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Messages.java
index d1a9fdc..e2cb159 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Messages.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Messages.java
@@ -26,6 +26,16 @@ public final class Messages {
 
     private static final String DOESNT_EXIST_MESSAGE_TEMPLATE = "%s %s doesn't exist";
 
+    private static final String TYPE_NOT_VALID_MESSAGE_TEMPLATE = "%s isn't a valid %s type, try with: %s";
+
+    private static final String ID_NOT_NUMBER_MESSAGE_TEMPLATE = "Error reading %s. It isn't a valid %s "
+            + "id because it isn't a long value";
+
+    private static final String NOT_BOOLEAN_MESSAGE_TEMPLATE = "Error reading %s. It isn't a valid %s "
+            + "value because it isn't a boolean value";
+
+    private static final String DEFAULT_MESSAGE_TEMPLATE = "%s is not a valid option. \n\b %s";
+
     public static void printCommandOptionMessage(final String message) {
         System.out.println(String.format(OPTION_COMMAND_MESSAGE_TEMPLATE, message));
     }
@@ -46,6 +56,26 @@ public final class Messages {
         printMessage(String.format(DELETED_MESSAGE_TEMPLATE, what, key));
     }
 
+    public static void printIdNotNumberDeletedMessage(final String what, final String key) {
+        printMessage(String.format(ID_NOT_NUMBER_MESSAGE_TEMPLATE, key, what));
+    }
+    
+    public static void printNotBooleanDeletedMessage(final String what, final String key) {
+        printMessage(String.format(NOT_BOOLEAN_MESSAGE_TEMPLATE, key, what));
+    }
+
+    public static void printTypeNotValidMessage(final String what, final String key, final String[] types) {
+        final StringBuilder typesBuilder = new StringBuilder();
+        for (final String type : types) {
+            typesBuilder.append("\n     *** ").append(type);
+        }
+        printMessage(String.format(TYPE_NOT_VALID_MESSAGE_TEMPLATE, key, what, typesBuilder.toString()));
+    }
+
+    public static void printDefaultMessage(final String option, final String helpMessage) {
+        printMessage(String.format(DEFAULT_MESSAGE_TEMPLATE, option, helpMessage));
+    }
+
     private Messages() {
 
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/2a99db9c/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java
index a20d0a7..a60a5af 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java
@@ -29,7 +29,7 @@ public enum TaskType {
     SYNCHRONIZATION("sync"),
     PUSH("push");
 
-    private String name;
+    private final String name;
 
     private TaskType(final String name) {
         this.name = name;


[33/54] [abbrv] syncope git commit: refactoring of installation process, SYNCOPE-158

Posted by fm...@apache.org.
refactoring of installation process, SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 4f543e8c045edf6a321a1ac2bcf4b4ac7755b620
Parents: 3f58b93
Author: massi <ma...@tirasa.net>
Authored: Wed Oct 21 12:28:40 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Wed Oct 21 12:28:40 2015 +0200

----------------------------------------------------------------------
 .../cli/commands/install/InstallCommand.java    | 215 +------------------
 .../commands/install/InstallResultManager.java  |  72 +++++++
 .../cli/commands/install/InstallSetup.java      | 161 ++++++++++++++
 3 files changed, 235 insertions(+), 213 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/4f543e8c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
index 533c1ce..0caba9f 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
@@ -18,21 +18,11 @@
  */
 package org.apache.syncope.client.cli.commands.install;
 
-import java.io.FileNotFoundException;
-import java.io.UnsupportedEncodingException;
-import java.net.ConnectException;
-import java.net.UnknownHostException;
-import java.util.Scanner;
-import javax.ws.rs.ProcessingException;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.client.cli.commands.AbstractCommand;
 import org.apache.syncope.client.cli.commands.logger.LoggerCommand;
-import org.apache.syncope.client.cli.util.FileSystemUtils;
-import org.apache.syncope.client.cli.util.JasyptUtils;
-import org.apache.syncope.common.rest.api.service.SyncopeService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,222 +36,21 @@ public class InstallCommand extends AbstractCommand {
             + "    --help \n"
             + "    --setup";
 
-    private String syncopeAdminUser;
-
-    private String syncopeAdminPassword;
-
-    private String syncopeServerSchema;
-
-    private String syncopeServerHostname = "localhost";
-
-    private String syncopeServerPort = "8080";
-
-    private String syncopeServerRestContext = "/syncope/rest/";
-
     @Override
     public void execute(final Input input) {
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
         if (StringUtils.isBlank(input.getOption())) {
             input.setOption(Options.HELP.getOptionName());
         }
 
         switch (Options.fromName(input.getOption())) {
             case INSTALL:
-                final Scanner scanIn = new Scanner(System.in);
-
-                System.out.println("");
-                System.out.println("###############################################");
-                System.out.println("#                                             #");
-                System.out.println("# Welcome to Syncope CLI installation process #");
-                System.out.println("#                                             #");
-                System.out.println("###############################################");
-                System.out.println("");
-
-                System.out.println("Path to config files of Syncope CLI client will be: "
-                        + InstallConfigFileTemplate.DIR_PATH);
-
-                if (!FileSystemUtils.canWrite(InstallConfigFileTemplate.DIR_PATH)) {
-                    System.out.println("Permission denied on " + InstallConfigFileTemplate.DIR_PATH);
-                    break;
-                }
-                System.out.println("- File system permission checked");
-                System.out.println("");
-
-                System.out.println("Syncope server schema [http/https]:");
-                String syncopeServerSchemaFromSystemIn = scanIn.nextLine();
-                boolean schemaFounded = false;
-                while (!schemaFounded) {
-                    if (("http".equalsIgnoreCase(syncopeServerSchemaFromSystemIn))
-                            || ("https".equalsIgnoreCase(syncopeServerSchemaFromSystemIn))) {
-                        syncopeServerSchema = syncopeServerSchemaFromSystemIn;
-                        schemaFounded = true;
-                    } else {
-                        System.out.println("Please use one of below values:");
-                        System.out.println("   - http");
-                        System.out.println("   - https");
-                        syncopeServerSchemaFromSystemIn = scanIn.nextLine();
-                    }
-                }
-
-                System.out.println("Syncope server hostname [e.g. " + syncopeServerHostname + "]:");
-                String syncopeServerHostnameFromSystemIn = scanIn.nextLine();
-                boolean syncopeServerHostnameFounded = false;
-                while (!syncopeServerHostnameFounded) {
-                    if (StringUtils.isNotBlank(syncopeServerHostnameFromSystemIn)) {
-                        syncopeServerHostname = syncopeServerHostnameFromSystemIn;
-                        syncopeServerHostnameFounded = true;
-                    } else {
-                        System.out.println("Syncope server hostname [e.g. " + syncopeServerHostname + "]:");
-                        syncopeServerHostnameFromSystemIn = scanIn.nextLine();
-                    }
-                }
-
-                System.out.println("Syncope server port [e.g. " + syncopeServerPort + "]:");
-                String syncopeServerPortFromSystemIn = scanIn.nextLine();
-                boolean syncopeServerPortFounded = false;
-                while (!syncopeServerPortFounded) {
-                    if (StringUtils.isNotBlank(syncopeServerPortFromSystemIn)) {
-                        syncopeServerPort = syncopeServerPortFromSystemIn;
-                        syncopeServerPortFounded = true;
-                    } else if (!StringUtils.isNumeric(syncopeServerPortFromSystemIn)) {
-                        System.out.println(syncopeServerPortFromSystemIn + " is not a numeric string, try again");
-                        syncopeServerPortFromSystemIn = scanIn.nextLine();
-                    } else {
-                        System.out.println("Syncope server port [e.g. " + syncopeServerPort + "]:");
-                        syncopeServerPortFromSystemIn = scanIn.nextLine();
-                    }
-                }
-
-                System.out.println("Syncope server rest context [e.g. " + syncopeServerRestContext + "]:");
-                String syncopeServerRestContextFromSystemIn = scanIn.nextLine();
-                boolean syncopeServerRestContextFounded = false;
-                while (!syncopeServerRestContextFounded) {
-                    if (StringUtils.isNotBlank(syncopeServerRestContextFromSystemIn)) {
-                        syncopeServerRestContext = syncopeServerRestContextFromSystemIn;
-                        syncopeServerRestContextFounded = true;
-                    } else {
-                        System.out.println("Syncope server port [e.g. " + syncopeServerRestContext + "]:");
-                        syncopeServerRestContextFromSystemIn = scanIn.nextLine();
-                    }
-                }
-
-                System.out.println("Syncope admin user:");
-                String syncopeAdminUserFromSystemIn = scanIn.nextLine();
-                boolean syncopeAdminUserFounded = false;
-                while (!syncopeAdminUserFounded) {
-                    if (StringUtils.isNotBlank(syncopeAdminUserFromSystemIn)) {
-                        syncopeAdminUser = syncopeAdminUserFromSystemIn;
-                        syncopeAdminUserFounded = true;
-                    } else {
-                        System.out.println("Syncope admin user:");
-                        syncopeAdminUserFromSystemIn = scanIn.nextLine();
-                    }
-                }
-
-                System.out.println("Syncope admin password:");
-                String syncopeAdminPasswordFromSystemIn = scanIn.nextLine();
-                boolean syncopeAdminPasswordFounded = false;
-                while (!syncopeAdminPasswordFounded) {
-                    if (StringUtils.isNotBlank(syncopeAdminPasswordFromSystemIn)) {
-                        syncopeAdminPassword = syncopeAdminPasswordFromSystemIn;
-                        syncopeAdminPasswordFounded = true;
-                    } else {
-                        System.out.println("Syncope admin user:");
-                        syncopeAdminPasswordFromSystemIn = scanIn.nextLine();
-                    }
-                }
-
-                scanIn.close();
-
-                final JasyptUtils jasyptUtils = JasyptUtils.getJasyptUtils();
-
-                try {
-                    FileSystemUtils.createNewDirectory(InstallConfigFileTemplate.DIR_PATH);
-                    final String contentCliPropertiesFile = InstallConfigFileTemplate.createFile(
-                            syncopeServerSchema,
-                            syncopeServerHostname,
-                            syncopeServerPort,
-                            syncopeServerRestContext,
-                            syncopeAdminUser,
-                            jasyptUtils.encrypt(syncopeAdminPassword));
-                    FileSystemUtils.createFileWith(InstallConfigFileTemplate.FILE_PATH, contentCliPropertiesFile);
-
-                } catch (final FileNotFoundException | UnsupportedEncodingException ex) {
-                    System.out.println(ex.getMessage());
-                }
-
-                try {
-                    final SyncopeService syncopeService = SyncopeServices.get(SyncopeService.class);
-                    System.out.println("Provided parameters checked on Syncope core version: "
-                            + syncopeService.info().getVersion());
-                    System.out.println("");
-                    System.out.println("###############################################");
-                    System.out.println("#                                             #");
-                    System.out.println("#           Installation successful           #");
-                    System.out.println("#     now you can use Syncope CLI client      #");
-                    System.out.println("#                                             #");
-                    System.out.println("###############################################");
-                    System.out.println("");
-                } catch (final ProcessingException ex) {
-                    if (ex.getCause() instanceof UnknownHostException) {
-                        final String unknownHost = ex.getCause().getMessage().split(":")[3];
-                        System.out.println("");
-                        System.out.println("Provided host:" + unknownHost);
-                        System.out.println("");
-                        System.out.println("###############################################");
-                        System.out.println("#                                             #");
-                        System.out.println("#            Provided unknown host!           #");
-                        System.out.println("#        START AGAIN the installation!        #");
-                        System.out.println("#                                             #");
-                        System.out.println("###############################################");
-                        System.out.println("");
-                    } else if (ex.getCause() instanceof ConnectException) {
-                        System.out.println("");
-                        System.out.println("Provided address :" + SyncopeServices.getAddress());
-                        System.out.println("");
-                        System.out.println("###############################################");
-                        System.out.println("#                                             #");
-                        System.out.println("#       Provided address is unreachable!      #");
-                        System.out.println("#         Check it and if it is wrong         #");
-                        System.out.println("#        START AGAIN the installation!        #");
-                        System.out.println("#                                             #");
-                        System.out.println("###############################################");
-                        System.out.println("");
-                    }
-                } catch (final Exception e) {
-                    if (e.getMessage().contains("not authenticated")) {
-                        System.out.println("");
-                        System.out.println("###############################################");
-                        System.out.println("#                                             #");
-                        System.out.println("#   Username or password provided are wrong   #");
-                        System.out.println("#        START AGAIN the installation!        #");
-                        System.out.println("#                                             #");
-                        System.out.println("###############################################");
-                        System.out.println("");
-                    } else {
-                        System.out.println("");
-                        System.out.println("###############################################");
-                        System.out.println("#                                             #");
-                        System.out.println("#                Something wrong              #");
-                        System.out.println("#        START AGAIN the installation!        #");
-                        System.out.println("#                                             #");
-                        System.out.println("###############################################");
-                        System.out.println("");
-                    }
-                }
+                new InstallSetup().setup();
                 break;
             case HELP:
                 System.out.println(HELP_MESSAGE);
                 break;
             default:
-                System.out.println(input.getOption() + " is not a valid option.");
-                System.out.println("");
-                System.out.println(HELP_MESSAGE);
+                new InstallResultManager().defaultError(input.getOption(), HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/4f543e8c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallResultManager.java
new file mode 100644
index 0000000..994aca6
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallResultManager.java
@@ -0,0 +1,72 @@
+package org.apache.syncope.client.cli.commands.install;
+
+import java.net.ConnectException;
+import java.net.UnknownHostException;
+import javax.ws.rs.ProcessingException;
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+
+public class InstallResultManager extends CommonsResultManager {
+
+    public void installationSuccessful(final String version) {
+        System.out.println("Installation parameters checked on Syncope core version: " + version);
+        System.out.println("");
+        System.out.println("###############################################");
+        System.out.println("#                                             #");
+        System.out.println("#           Installation successful           #");
+        System.out.println("#     now you can use Syncope CLI client      #");
+        System.out.println("#                                             #");
+        System.out.println("###############################################");
+        System.out.println("");
+    }
+
+    public void manageProcessingException(final ProcessingException ex) {
+        if (ex.getCause() instanceof UnknownHostException) {
+            final String unknownHost = ex.getCause().getMessage().split(":")[3];
+            System.out.println("");
+            System.out.println("Provided host:" + unknownHost);
+            System.out.println("");
+            System.out.println("###############################################");
+            System.out.println("#                                             #");
+            System.out.println("#            Provided unknown host!           #");
+            System.out.println("#        START AGAIN the installation!        #");
+            System.out.println("#                                             #");
+            System.out.println("###############################################");
+            System.out.println("");
+        } else if (ex.getCause() instanceof ConnectException) {
+            System.out.println("");
+            System.out.println("Provided address :" + SyncopeServices.getAddress());
+            System.out.println("");
+            System.out.println("###############################################");
+            System.out.println("#                                             #");
+            System.out.println("#       Provided address is unreachable!      #");
+            System.out.println("#         Check it and if it is wrong         #");
+            System.out.println("#        START AGAIN the installation!        #");
+            System.out.println("#                                             #");
+            System.out.println("###############################################");
+            System.out.println("");
+        }
+    }
+
+    public void manageException(final Exception e) {
+        if (e.getMessage().contains("not authenticated")) {
+            System.out.println("");
+            System.out.println("###############################################");
+            System.out.println("#                                             #");
+            System.out.println("#   Username or password provided are wrong   #");
+            System.out.println("#        START AGAIN the installation!        #");
+            System.out.println("#                                             #");
+            System.out.println("###############################################");
+            System.out.println("");
+        } else {
+            System.out.println("");
+            System.out.println("###############################################");
+            System.out.println("#                                             #");
+            System.out.println("#                Something wrong              #");
+            System.out.println("#        START AGAIN the installation!        #");
+            System.out.println("#                                             #");
+            System.out.println("###############################################");
+            System.out.println("");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4f543e8c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
new file mode 100644
index 0000000..2a4079e
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
@@ -0,0 +1,161 @@
+package org.apache.syncope.client.cli.commands.install;
+
+import java.io.FileNotFoundException;
+import java.io.UnsupportedEncodingException;
+import java.util.Scanner;
+import javax.ws.rs.ProcessingException;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.client.cli.util.FileSystemUtils;
+import org.apache.syncope.client.cli.util.JasyptUtils;
+import org.apache.syncope.common.rest.api.service.SyncopeService;
+
+public class InstallSetup {
+
+    private final InstallResultManager installResultManager = new InstallResultManager();
+
+    private String syncopeAdminUser;
+
+    private String syncopeAdminPassword;
+
+    private String syncopeServerSchema;
+
+    private String syncopeServerHostname = "localhost";
+
+    private String syncopeServerPort = "8080";
+
+    private String syncopeServerRestContext = "/syncope/rest/";
+
+    public void setup() {
+        final Scanner scanIn = new Scanner(System.in);
+
+        System.out.println("");
+        System.out.println("###############################################");
+        System.out.println("#                                             #");
+        System.out.println("# Welcome to Syncope CLI installation process #");
+        System.out.println("#                                             #");
+        System.out.println("###############################################");
+        System.out.println("");
+
+        System.out.println("Path to config files of Syncope CLI client will be: "
+                + InstallConfigFileTemplate.DIR_PATH);
+
+        if (!FileSystemUtils.canWrite(InstallConfigFileTemplate.DIR_PATH)) {
+            System.out.println("Permission denied on " + InstallConfigFileTemplate.DIR_PATH);
+        }
+        System.out.println("- File system permission checked");
+        System.out.println("");
+
+        System.out.println("Syncope server schema [http/https]:");
+        String syncopeServerSchemaFromSystemIn = scanIn.nextLine();
+        boolean schemaFounded = false;
+        while (!schemaFounded) {
+            if (("http".equalsIgnoreCase(syncopeServerSchemaFromSystemIn))
+                    || ("https".equalsIgnoreCase(syncopeServerSchemaFromSystemIn))) {
+                syncopeServerSchema = syncopeServerSchemaFromSystemIn;
+                schemaFounded = true;
+            } else {
+                System.out.println("Please use one of below values:");
+                System.out.println("   - http");
+                System.out.println("   - https");
+                syncopeServerSchemaFromSystemIn = scanIn.nextLine();
+            }
+        }
+
+        System.out.println("Syncope server hostname [e.g. " + syncopeServerHostname + "]:");
+        String syncopeServerHostnameFromSystemIn = scanIn.nextLine();
+        boolean syncopeServerHostnameFounded = false;
+        while (!syncopeServerHostnameFounded) {
+            if (StringUtils.isNotBlank(syncopeServerHostnameFromSystemIn)) {
+                syncopeServerHostname = syncopeServerHostnameFromSystemIn;
+                syncopeServerHostnameFounded = true;
+            } else {
+                System.out.println("Syncope server hostname [e.g. " + syncopeServerHostname + "]:");
+                syncopeServerHostnameFromSystemIn = scanIn.nextLine();
+            }
+        }
+
+        System.out.println("Syncope server port [e.g. " + syncopeServerPort + "]:");
+        String syncopeServerPortFromSystemIn = scanIn.nextLine();
+        boolean syncopeServerPortFounded = false;
+        while (!syncopeServerPortFounded) {
+            if (StringUtils.isNotBlank(syncopeServerPortFromSystemIn)) {
+                syncopeServerPort = syncopeServerPortFromSystemIn;
+                syncopeServerPortFounded = true;
+            } else if (!StringUtils.isNumeric(syncopeServerPortFromSystemIn)) {
+                System.out.println(syncopeServerPortFromSystemIn + " is not a numeric string, try again");
+                syncopeServerPortFromSystemIn = scanIn.nextLine();
+            } else {
+                System.out.println("Syncope server port [e.g. " + syncopeServerPort + "]:");
+                syncopeServerPortFromSystemIn = scanIn.nextLine();
+            }
+        }
+
+        System.out.println("Syncope server rest context [e.g. " + syncopeServerRestContext + "]:");
+        String syncopeServerRestContextFromSystemIn = scanIn.nextLine();
+        boolean syncopeServerRestContextFounded = false;
+        while (!syncopeServerRestContextFounded) {
+            if (StringUtils.isNotBlank(syncopeServerRestContextFromSystemIn)) {
+                syncopeServerRestContext = syncopeServerRestContextFromSystemIn;
+                syncopeServerRestContextFounded = true;
+            } else {
+                System.out.println("Syncope server port [e.g. " + syncopeServerRestContext + "]:");
+                syncopeServerRestContextFromSystemIn = scanIn.nextLine();
+            }
+        }
+
+        System.out.println("Syncope admin user:");
+        String syncopeAdminUserFromSystemIn = scanIn.nextLine();
+        boolean syncopeAdminUserFounded = false;
+        while (!syncopeAdminUserFounded) {
+            if (StringUtils.isNotBlank(syncopeAdminUserFromSystemIn)) {
+                syncopeAdminUser = syncopeAdminUserFromSystemIn;
+                syncopeAdminUserFounded = true;
+            } else {
+                System.out.println("Syncope admin user:");
+                syncopeAdminUserFromSystemIn = scanIn.nextLine();
+            }
+        }
+
+        System.out.println("Syncope admin password:");
+        String syncopeAdminPasswordFromSystemIn = scanIn.nextLine();
+        boolean syncopeAdminPasswordFounded = false;
+        while (!syncopeAdminPasswordFounded) {
+            if (StringUtils.isNotBlank(syncopeAdminPasswordFromSystemIn)) {
+                syncopeAdminPassword = syncopeAdminPasswordFromSystemIn;
+                syncopeAdminPasswordFounded = true;
+            } else {
+                System.out.println("Syncope admin user:");
+                syncopeAdminPasswordFromSystemIn = scanIn.nextLine();
+            }
+        }
+
+        scanIn.close();
+
+        final JasyptUtils jasyptUtils = JasyptUtils.getJasyptUtils();
+
+        try {
+            FileSystemUtils.createNewDirectory(InstallConfigFileTemplate.DIR_PATH);
+            final String contentCliPropertiesFile = InstallConfigFileTemplate.createFile(
+                    syncopeServerSchema,
+                    syncopeServerHostname,
+                    syncopeServerPort,
+                    syncopeServerRestContext,
+                    syncopeAdminUser,
+                    jasyptUtils.encrypt(syncopeAdminPassword));
+            FileSystemUtils.createFileWith(InstallConfigFileTemplate.FILE_PATH, contentCliPropertiesFile);
+
+        } catch (final FileNotFoundException | UnsupportedEncodingException ex) {
+            System.out.println(ex.getMessage());
+        }
+
+        try {
+            final SyncopeService syncopeService = SyncopeServices.get(SyncopeService.class);
+            installResultManager.installationSuccessful(syncopeService.info().getVersion());
+        } catch (final ProcessingException ex) {
+            installResultManager.manageProcessingException(ex);
+        } catch (final Exception e) {
+            installResultManager.manageException(e);
+        }
+    }
+}


[47/54] [abbrv] syncope git commit: [SYNCOPE-715] Implemented

Posted by fm...@apache.org.
[SYNCOPE-715] Implemented


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

Branch: refs/heads/SYNCOPE-156
Commit: fa5e65aa95fae91387d3c1ba4992ceb5bd3e4b6c
Parents: e20dd0a
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 22 13:59:44 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 22 13:59:44 2015 +0200

----------------------------------------------------------------------
 .../apache/syncope/core/logic/UserLogic.java    | 27 ++++++-------
 .../core/persistence/jpa/dao/JPAConfDAO.java    | 28 +++++++------
 .../main/resources/domains/MasterContent.xml    |  6 +++
 .../persistence/jpa/inner/MultitenancyTest.java |  2 +-
 .../persistence/jpa/inner/PlainSchemaTest.java  |  2 +-
 .../test/resources/domains/MasterContent.xml    |  8 +++-
 .../src/test/resources/domains/TwoContent.xml   |  6 +++
 .../provisioning/api/data/UserDataBinder.java   |  2 +
 .../java/data/UserDataBinderImpl.java           |  9 +++++
 .../fit/core/reference/MultitenancyITCase.java  |  2 +-
 .../fit/core/reference/SyncTaskITCase.java      | 41 +++++++++-----------
 .../syncope/fit/core/reference/UserITCase.java  |  8 ++--
 12 files changed, 87 insertions(+), 54 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
index 776f427..deab762 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
@@ -121,7 +121,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
                     @Override
                     public UserTO transform(final User input) {
-                        return binder.getUserTO(input, details);
+                        return binder.returnUserTO(binder.getUserTO(input, details));
                     }
                 }, new ArrayList<UserTO>());
     }
@@ -131,14 +131,14 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     public Pair<String, UserTO> readSelf() {
         return ImmutablePair.of(
                 POJOHelper.serialize(AuthContextUtils.getAuthorizations()),
-                binder.getAuthenticatedUserTO());
+                binder.returnUserTO(binder.getAuthenticatedUserTO()));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_READ + "')")
     @Transactional(readOnly = true)
     @Override
     public UserTO read(final Long key) {
-        return binder.getUserTO(key);
+        return binder.returnUserTO(binder.getUserTO(key));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_SEARCH + "')")
@@ -163,7 +163,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
             @Override
             public UserTO transform(final User input) {
-                return binder.getUserTO(input, details);
+                return binder.returnUserTO(binder.getUserTO(input, details));
             }
         }, new ArrayList<UserTO>());
     }
@@ -203,7 +203,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
         UserTO savedTO = binder.getUserTO(created.getKey());
         savedTO.getPropagationStatusTOs().addAll(created.getValue());
 
-        return afterCreate(savedTO, before.getValue());
+        return binder.returnUserTO(afterCreate(savedTO, before.getValue()));
     }
 
     @PreAuthorize("isAuthenticated() and not(hasRole('" + Entitlement.ANONYMOUS + "'))")
@@ -240,7 +240,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
         UserTO updatedTO = binder.getUserTO(updated.getKey());
         updatedTO.getPropagationStatusTOs().addAll(updated.getValue());
 
-        return afterUpdate(updatedTO, before.getRight());
+        return binder.returnUserTO(afterUpdate(updatedTO, before.getRight()));
     }
 
     protected Map.Entry<Long, List<PropagationStatus>> setStatusOnWfAdapter(final StatusPatch statusPatch) {
@@ -277,7 +277,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
         Map.Entry<Long, List<PropagationStatus>> updated = setStatusOnWfAdapter(statusPatch);
         UserTO savedTO = binder.getUserTO(updated.getKey());
         savedTO.getPropagationStatusTOs().addAll(updated.getValue());
-        return savedTO;
+        return binder.returnUserTO(savedTO);
     }
 
     @PreAuthorize("hasRole('" + Entitlement.MUST_CHANGE_PASSWORD + "')")
@@ -366,7 +366,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
         }
         deletedTO.getPropagationStatusTOs().addAll(statuses);
 
-        return afterDelete(deletedTO, before.getRight());
+        return binder.returnUserTO(afterDelete(deletedTO, before.getRight()));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
@@ -389,7 +389,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
             }
         }));
 
-        return binder.getUserTO(provisioningManager.unlink(patch));
+        return binder.returnUserTO(binder.getUserTO(provisioningManager.unlink(patch)));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
@@ -412,7 +412,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
             }
         }));
 
-        return binder.getUserTO(provisioningManager.link(patch));
+        return binder.returnUserTO(binder.getUserTO(provisioningManager.link(patch)));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
@@ -485,7 +485,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
         UserTO updatedTO = binder.getUserTO(key);
         updatedTO.getPropagationStatusTOs().addAll(statuses);
-        return updatedTO;
+        return binder.returnUserTO(updatedTO);
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
@@ -504,7 +504,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
 
         user.getPropagationStatusTOs().addAll(provisioningManager.provision(key, changePwd, password, resources));
-        return user;
+        return binder.returnUserTO(user);
     }
 
     @Override
@@ -527,7 +527,8 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
         if ((key != null) && !key.equals(0L)) {
             try {
-                return key instanceof Long ? binder.getUserTO((Long) key) : binder.getUserTO((String) key);
+                return binder.returnUserTO(key instanceof Long
+                        ? binder.getUserTO((Long) key) : binder.getUserTO((String) key));
             } catch (Throwable ignore) {
                 LOG.debug("Unresolved reference", ignore);
                 throw new UnresolvedReferenceException(ignore);

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
index 4afe78e..985c7aa 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
@@ -22,6 +22,7 @@ import org.apache.syncope.core.persistence.api.dao.ConfDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.conf.Conf;
 import org.apache.syncope.core.persistence.jpa.entity.conf.JPACPlainAttr;
@@ -64,19 +65,22 @@ public class JPAConfDAO extends AbstractDAO<Conf, Long> implements ConfDAO {
     public CPlainAttr find(final String key, final String defaultValue) {
         CPlainAttr result = find(key);
         if (result == null) {
-            JPACPlainAttr newAttr = new JPACPlainAttr();
-            newAttr.setSchema(schemaDAO.find(key));
-
-            JPACPlainAttrValue attrValue;
-            if (newAttr.getSchema().isUniqueConstraint()) {
-                attrValue = new JPACPlainAttrValue();
-                ((PlainAttrUniqueValue) attrValue).setSchema(newAttr.getSchema());
-            } else {
-                attrValue = new JPACPlainAttrValue();
+            PlainSchema schema = schemaDAO.find(key);
+            if (schema != null) {
+                JPACPlainAttr newAttr = new JPACPlainAttr();
+                newAttr.setSchema(schemaDAO.find(key));
+
+                JPACPlainAttrValue attrValue;
+                if (newAttr.getSchema().isUniqueConstraint()) {
+                    attrValue = new JPACPlainAttrValue();
+                    ((PlainAttrUniqueValue) attrValue).setSchema(newAttr.getSchema());
+                } else {
+                    attrValue = new JPACPlainAttrValue();
+                }
+                newAttr.add(defaultValue, attrValue);
+
+                result = newAttr;
             }
-            newAttr.add(defaultValue, attrValue);
-
-            result = newAttr;
         }
 
         return result;

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/domains/MasterContent.xml b/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
index 92216fd..ed1c035 100644
--- a/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
@@ -85,6 +85,12 @@ under the License.
   <CPlainAttr id="12" owner_id="1" schema_name="tasks.interruptMaxRetries"/>
   <CPlainAttrValue id="12" attribute_id="12" longValue="20"/>
 
+  <!-- Return hashed password values when reading users -->
+  <PlainSchema name="return.password.value" type="Boolean"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <CPlainAttr id="14" owner_id="1" schema_name="return.password.value"/>
+  <CPlainAttrValue id="14" attribute_id="14" booleanValue="0"/>
+
   <AnyType name="USER" kind="USER"/>
   <AnyTypeClass name="BaseUser"/>
   <AnyType_AnyTypeClass anyType_name="USER" anyTypeClass_name="BaseUser"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
index 074c26e..7d1dfea 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
@@ -83,7 +83,7 @@ public class MultitenancyTest extends AbstractTest {
 
     @Test
     public void readPlainSchemas() {
-        assertEquals(16, plainSchemaDAO.findAll().size());
+        assertEquals(17, plainSchemaDAO.findAll().size());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
index c425460..21636b7 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
@@ -47,7 +47,7 @@ public class PlainSchemaTest extends AbstractTest {
     @Test
     public void findAll() {
         List<PlainSchema> schemas = plainSchemaDAO.findAll();
-        assertEquals(43, schemas.size());
+        assertEquals(44, schemas.size());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 96e606f..d1fde9e 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -84,7 +84,13 @@ under the License.
                mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
   <CPlainAttr id="12" owner_id="1" schema_name="tasks.interruptMaxRetries"/>
   <CPlainAttrValue id="12" attribute_id="12" longValue="20"/>
-
+  
+  <!-- Return hashed password values when reading users -->
+  <PlainSchema name="return.password.value" type="Boolean"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <CPlainAttr id="14" owner_id="1" schema_name="return.password.value"/>
+  <CPlainAttrValue id="14" attribute_id="14" booleanValue="0"/>
+  
   <!-- For usage with admin console -->
   <PlainSchema name="admin.user.layout" type="String"
                mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/TwoContent.xml b/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
index cce2ec8..cc36a9d 100644
--- a/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
@@ -71,6 +71,12 @@ under the License.
   <CPlainAttr id="12" owner_id="1" schema_name="tasks.interruptMaxRetries"/>
   <CPlainAttrValue id="12" attribute_id="12" longValue="20"/>
 
+  <!-- Return hashed password values when reading users -->
+  <PlainSchema name="return.password.value" type="Boolean"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <CPlainAttr id="14" owner_id="1" schema_name="return.password.value"/>
+  <CPlainAttrValue id="14" attribute_id="14" booleanValue="0"/>
+  
   <AnyType name="USER" kind="USER"/>
   <AnyTypeClass name="BaseUser"/>
   <AnyType_AnyTypeClass anyType_name="USER" anyTypeClass_name="BaseUser"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/UserDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/UserDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/UserDataBinder.java
index ff645f4..9592a3f 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/UserDataBinder.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/UserDataBinder.java
@@ -25,6 +25,8 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 
 public interface UserDataBinder {
 
+    UserTO returnUserTO(UserTO userTO);
+
     UserTO getAuthenticatedUserTO();
 
     UserTO getUserTO(String username);

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index 4bb7bdf..147683c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -101,6 +101,15 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
 
     @Transactional(readOnly = true)
     @Override
+    public UserTO returnUserTO(final UserTO userTO) {
+        if (!confDAO.find("return.password.value", "false").getValues().get(0).getBooleanValue()) {
+            userTO.setPassword(null);
+        }
+        return userTO;
+    }
+
+    @Transactional(readOnly = true)
+    @Override
     public UserTO getAuthenticatedUserTO() {
         final UserTO authUserTO;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/MultitenancyITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/MultitenancyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/MultitenancyITCase.java
index c1ce3b0..9a54b7f 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/MultitenancyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/MultitenancyITCase.java
@@ -98,7 +98,7 @@ public class MultitenancyITCase extends AbstractITCase {
 
     @Test
     public void readPlainSchemas() {
-        assertEquals(16, adminClient.getService(SchemaService.class).list(SchemaType.PLAIN).size());
+        assertEquals(17, adminClient.getService(SchemaService.class).list(SchemaType.PLAIN).size());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
index d645c77..e8ffd56 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
@@ -28,11 +28,13 @@ import static org.junit.Assert.fail;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
 import javax.ws.rs.core.Response;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.SerializationUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
@@ -674,9 +676,9 @@ public class SyncTaskITCase extends AbstractTaskITCase {
         assertEquals(Encryptor.getInstance().encode("security123", CipherAlgorithm.SHA1), value.toUpperCase());
 
         // 3. Update the password in the DB
-        String newPassword = Encryptor.getInstance().encode("new-security", CipherAlgorithm.SHA1);
-        jdbcTemplate.execute(
-                "UPDATE test set PASSWORD='" + newPassword + "' where ID='" + user.getUsername() + "'");
+        String newCleanPassword = "new-security";
+        String newPassword = Encryptor.getInstance().encode(newCleanPassword, CipherAlgorithm.SHA1);
+        jdbcTemplate.execute("UPDATE test set PASSWORD='" + newPassword + "' where ID='" + user.getUsername() + "'");
 
         // 4. Sync the user from the resource
         SyncTaskTO syncTask = new SyncTaskTO();
@@ -701,8 +703,8 @@ public class SyncTaskITCase extends AbstractTaskITCase {
         assertEquals(PropagationTaskExecStatus.SUCCESS, PropagationTaskExecStatus.valueOf(execution.getStatus()));
 
         // 5. Test the sync'd user
-        UserTO updatedUser = userService.read(user.getKey());
-        assertEquals(newPassword, updatedUser.getPassword());
+        Pair<Map<String, Set<String>>, UserTO> self = clientFactory.create(user.getUsername(), newCleanPassword).self();
+        assertNotNull(self);
 
         // 6. Delete SyncTask + user
         taskService.delete(syncTask.getKey());
@@ -715,30 +717,31 @@ public class SyncTaskITCase extends AbstractTaskITCase {
         ldapCleanup();
 
         // 1. create user in LDAP
+        String oldCleanPassword = "security123";
         UserTO user = UserITCase.getUniqueSampleTO("syncope313-ldap@syncope.apache.org");
-        user.setPassword("security123");
+        user.setPassword(oldCleanPassword);
         user.getResources().add(RESOURCE_NAME_LDAP);
         user = createUser(user);
         assertNotNull(user);
         assertFalse(user.getResources().isEmpty());
 
         // 2. request to change password only on Syncope and not on LDAP
+        String newCleanPassword = "new-security123";
         UserPatch userPatch = new UserPatch();
         userPatch.setKey(user.getKey());
-        userPatch.setPassword(new PasswordPatch.Builder().value("new-security123").build());
-        updateUser(userPatch);
+        userPatch.setPassword(new PasswordPatch.Builder().value(newCleanPassword).build());
+        user = updateUser(userPatch);
 
         // 3. Check that the Syncope user now has the changed password
-        UserTO updatedUser = userService.read(user.getKey());
-        String encodedNewPassword = Encryptor.getInstance().encode("new-security123", CipherAlgorithm.SHA1);
-        assertEquals(encodedNewPassword, updatedUser.getPassword());
+        Pair<Map<String, Set<String>>, UserTO> self = clientFactory.create(user.getUsername(), newCleanPassword).self();
+        assertNotNull(self);
 
         // 4. Check that the LDAP resource has the old password
         ConnObjectTO connObject =
                 resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), user.getKey());
         assertNotNull(getLdapRemoteObject(
                 connObject.getPlainAttrMap().get(Name.NAME).getValues().get(0),
-                "security123",
+                oldCleanPassword,
                 connObject.getPlainAttrMap().get(Name.NAME).getValues().get(0)));
 
         // 5. Update the LDAP Connector to retrieve passwords
@@ -761,27 +764,21 @@ public class SyncTaskITCase extends AbstractTaskITCase {
         syncTask.getActionsClassNames().add(LDAPPasswordSyncActions.class.getName());
         Response taskResponse = taskService.create(syncTask);
 
-        SyncTaskTO actual = getObject(taskResponse.getLocation(), TaskService.class, SyncTaskTO.class);
-        assertNotNull(actual);
-
-        syncTask = taskService.read(actual.getKey());
+        syncTask = getObject(taskResponse.getLocation(), TaskService.class, SyncTaskTO.class);
         assertNotNull(syncTask);
-        assertEquals(actual.getKey(), syncTask.getKey());
-        assertEquals(actual.getJobDelegateClassName(), syncTask.getJobDelegateClassName());
 
         TaskExecTO execution = execProvisioningTask(taskService, syncTask.getKey(), 50, false);
         assertEquals(PropagationTaskExecStatus.SUCCESS, PropagationTaskExecStatus.valueOf(execution.getStatus()));
 
         // 7. Test the sync'd user
-        String syncedPassword = Encryptor.getInstance().encode("security123", CipherAlgorithm.SHA1);
-        updatedUser = userService.read(user.getKey());
-        assertEquals(syncedPassword, updatedUser.getPassword());
+        self = clientFactory.create(user.getUsername(), oldCleanPassword).self();
+        assertNotNull(self);
 
         // 8. Delete SyncTask + user + reset the connector
         taskService.delete(syncTask.getKey());
         property.getValues().clear();
         property.getValues().add(Boolean.FALSE);
         connectorService.update(resourceConnector);
-        deleteUser(updatedUser.getKey());
+        deleteUser(user.getKey());
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/fa5e65aa/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
index 91da759..ebaf02b 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java
@@ -569,6 +569,7 @@ public class UserITCase extends AbstractITCase {
         UserTO userTO = userService.read(1L);
 
         assertNotNull(userTO);
+        assertNull(userTO.getPassword());
         assertNotNull(userTO.getPlainAttrs());
         assertFalse(userTO.getPlainAttrs().isEmpty());
     }
@@ -2352,14 +2353,15 @@ public class UserITCase extends AbstractITCase {
         userTO = createUser(userTO);
         assertNotNull(userTO);
 
-        connObjectTO =
-                resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), userTO.getKey());
+        connObjectTO = resourceService.readConnObject(RESOURCE_NAME_CSV, AnyTypeKind.USER.name(), userTO.getKey());
         assertNotNull(connObjectTO);
 
         // check if password has been correctly propagated on Syncope and resource-csv as usual
         assertEquals("passwordTESTNULL1", connObjectTO.getPlainAttrMap().
                 get(OperationalAttributes.PASSWORD_NAME).getValues().get(0));
-        assertNotNull(userTO.getPassword());
+        Pair<Map<String, Set<String>>, UserTO> self =
+                clientFactory.create(userTO.getUsername(), "passwordTESTNULL1").self();
+        assertNotNull(self);
 
         // 4. add password policy to resource with passwordNotStore to false --> must store password
         ResourceTO csv = resourceService.read(RESOURCE_NAME_CSV);


[39/54] [abbrv] syncope git commit: Complete JRebel profile on fit/console-reference

Posted by fm...@apache.org.
Complete JRebel profile on fit/console-reference


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

Branch: refs/heads/SYNCOPE-156
Commit: ef28d8e680f2003d99eaf5eb7f3c5af027a99cc6
Parents: 80f2548
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 15 12:34:26 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 22 11:40:32 2015 +0200

----------------------------------------------------------------------
 fit/console-reference/pom.xml | 70 ++++++++++++++++++++++++++++++++++++++
 fit/core-reference/pom.xml    |  1 +
 2 files changed, 71 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/ef28d8e6/fit/console-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/console-reference/pom.xml b/fit/console-reference/pom.xml
index 7227f04..b518886 100644
--- a/fit/console-reference/pom.xml
+++ b/fit/console-reference/pom.xml
@@ -453,6 +453,71 @@ ORYX.Editor.createByUrl = function(modelUrl){"/>
                   <resource>
                     <directory>${basedir}/../../common/rest-api/target/classes</directory>
                   </resource>
+
+                  <resource>
+                    <directory>${basedir}/../../core/logic/target/classes</directory>
+                    <excludes>
+                      <exclude>*Context.xml</exclude>
+                    </excludes>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../core/rest-cxf/target/classes</directory>
+                    <excludes>
+                      <exclude>*Context.xml</exclude>
+                    </excludes>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../core/misc/target/classes</directory>
+                    <excludes>
+                      <exclude>*Context.xml</exclude>
+                    </excludes>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../core/persistence-api/target/classes</directory>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../core/persistence-jpa/target/classes</directory>
+                    <excludes>
+                      <exclude>*Context.xml</exclude>
+                    </excludes>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../core/provisioning-api/target/classes</directory>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../core/provisioning-java/target/classes</directory>
+                    <excludes>
+                      <exclude>*Context.xml</exclude>
+                    </excludes>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../core/workflow-api/target/classes</directory>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../core/workflow-java/target/classes</directory>
+                    <excludes>
+                      <exclude>*Context.xml</exclude>
+                    </excludes>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../core/workflow-activiti/target/classes</directory>
+                    <excludes>
+                      <exclude>*Context.xml</exclude>
+                    </excludes>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../ext/camel/provisioning-camel/target/classes</directory>
+                    <excludes>
+                      <exclude>*Context.xml</exclude>
+                    </excludes>
+                  </resource>
+
+                  <resource>
+                    <directory>${basedir}/../../common/lib/target/classes</directory>
+                  </resource>
+                  <resource>
+                    <directory>${basedir}/../../common/rest-api/target/classes</directory>
+                  </resource>
                   <resource>
                     <directory>${basedir}/../../core/logic/target/classes</directory>
                     <excludes>
@@ -523,6 +588,11 @@ ORYX.Editor.createByUrl = function(modelUrl){"/>
                 <resources>
                   <resource>
                     <target>/</target>
+                    <directory>${basedir}/../../ext/swagger-ui/target/classes/META-INF/resources</directory>
+                  </resource>
+
+                  <resource>
+                    <target>/</target>
                     <directory>${basedir}/../../client/console/target/classes/META-INF/resources/</directory>
                   </resource>
                   <resource>

http://git-wip-us.apache.org/repos/asf/syncope/blob/ef28d8e6/fit/core-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 8f4f62a..7e0fd9f 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -754,6 +754,7 @@ under the License.
                   <resource>
                     <directory>${basedir}/../../common/rest-api/target/classes</directory>
                   </resource>
+
                   <resource>
                     <directory>${basedir}/../../core/logic/target/classes</directory>
                     <excludes>


[29/54] [abbrv] syncope git commit: checkstyle plugin told me to delete a private modifier

Posted by fm...@apache.org.
checkstyle plugin told me to delete a private modifier


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

Branch: refs/heads/SYNCOPE-156
Commit: 5ebdcf7f5109d8a778b843424bbb4c0adda7fe66
Parents: 85d4e83
Author: massi <ma...@tirasa.net>
Authored: Tue Oct 20 15:03:05 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Tue Oct 20 15:03:05 2015 +0200

----------------------------------------------------------------------
 .../apache/syncope/client/cli/commands/logger/LoggerCommand.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/5ebdcf7f/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
index 399723b..34acc25 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
@@ -94,7 +94,7 @@ public class LoggerCommand extends AbstractCommand {
 
         private final String optionName;
 
-        private static LoggerOptions(final String optionName) {
+        LoggerOptions(final String optionName) {
             this.optionName = optionName;
         }
 


[20/54] [abbrv] syncope git commit: Upgrading surefire, failsafe and checkstyle plugins

Posted by fm...@apache.org.
Upgrading surefire, failsafe and checkstyle plugins


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

Branch: refs/heads/SYNCOPE-156
Commit: 4e0783e1c331a763313b3cd4b82de8fc8b791e97
Parents: 1c459bf 503097d
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Mon Oct 19 16:36:06 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Mon Oct 19 16:36:06 2015 +0200

----------------------------------------------------------------------
 .../syncope/client/cli/commands/ConfigurationCommand.java    | 2 +-
 .../apache/syncope/client/cli/commands/DomainCommand.java    | 2 +-
 .../org/apache/syncope/client/cli/commands/HelpCommand.java  | 2 +-
 .../org/apache/syncope/client/cli/commands/InfoCommand.java  | 2 +-
 .../apache/syncope/client/cli/commands/LoggerCommand.java    | 2 +-
 .../syncope/client/cli/commands/NotificationCommand.java     | 2 +-
 .../apache/syncope/client/cli/commands/PolicyCommand.java    | 2 +-
 .../apache/syncope/client/cli/commands/ReportCommand.java    | 2 +-
 .../apache/syncope/client/cli/commands/SchemaCommand.java    | 2 +-
 .../org/apache/syncope/client/cli/commands/TaskCommand.java  | 2 +-
 .../syncope/client/cli/commands/install/InstallCommand.java  | 2 +-
 .../console/commons/SortableAnyProviderComparator.java       | 2 +-
 .../apache/syncope/client/console/commons/status/Status.java | 2 +-
 .../java/org/apache/syncope/client/console/pages/Login.java  | 4 ++--
 .../syncope/client/console/pages/ProvisioningModalPage.java  | 2 +-
 .../apache/syncope/client/console/pages/StatusModalPage.java | 2 +-
 .../syncope/client/console/panels/ResourceSecurityPanel.java | 2 +-
 .../org/apache/syncope/client/console/topology/Topology.java | 2 +-
 .../syncope/client/console/topology/WebSocketBehavior.java   | 4 ++--
 .../client/console/wicket/markup/html/form/ActionLink.java   | 2 +-
 .../console/wizards/provision/ProvisionWizardBuilder.java    | 6 +++---
 .../apache/syncope/client/lib/SyncopeClientFactoryBean.java  | 2 +-
 .../org/apache/syncope/common/lib/types/AnyTypeKind.java     | 2 +-
 .../apache/syncope/common/lib/types/ClientExceptionType.java | 2 +-
 .../org/apache/syncope/common/lib/types/IntMappingType.java  | 2 +-
 .../java/org/apache/syncope/common/lib/types/TaskType.java   | 2 +-
 .../java/org/apache/syncope/common/rest/api/Preference.java  | 2 +-
 .../java/org/apache/syncope/core/logic/AbstractAnyLogic.java | 2 +-
 .../org/apache/syncope/core/logic/init/LoggerLoader.java     | 2 +-
 .../syncope/core/misc/jexl/ClassFreeUberspectImpl.java       | 2 +-
 .../syncope/core/persistence/api/ImplementationLookup.java   | 2 +-
 .../core/persistence/jpa/content/ContentLoaderHandler.java   | 2 +-
 .../core/persistence/jpa/content/MultiParentNode.java        | 2 +-
 .../syncope/core/persistence/jpa/dao/SearchSupport.java      | 2 +-
 .../syncope/client/console/panels/CamelRoutePanel.java       | 2 +-
 .../java/org/apache/syncope/installer/enums/Containers.java  | 2 +-
 .../main/java/org/apache/syncope/installer/enums/DBs.java    | 2 +-
 pom.xml                                                      | 8 ++++----
 38 files changed, 45 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
index ee225d7,0000000..8a6c7b5
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
@@@ -1,319 -1,0 +1,319 @@@
 +/*
 + * 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.cli.commands;
 +
 +import java.io.FileNotFoundException;
 +import java.io.IOException;
 +import java.io.SequenceInputStream;
 +import java.util.ArrayList;
 +import java.util.List;
 +import javax.xml.parsers.ParserConfigurationException;
 +import javax.xml.transform.TransformerConfigurationException;
 +import javax.xml.transform.TransformerException;
 +import javax.xml.ws.WebServiceException;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.SyncopeServices;
 +import org.apache.syncope.client.cli.messages.Messages;
 +import org.apache.syncope.client.cli.util.XMLUtils;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.to.AttrTO;
 +import org.apache.syncope.common.lib.to.ConfTO;
 +import org.apache.syncope.common.rest.api.service.ConfigurationService;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.xml.sax.SAXException;
 +
 +@Command(name = "configuration")
 +public class ConfigurationCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(ConfigurationCommand.class);
 +
 +    private static final String EXPORT_FILE_NAME = "/content.xml";
 +
 +    private static final String HELP_MESSAGE = "Usage: configuration [options]\n"
 +            + "  Options:\n"
 +            + "    --help \n"
 +            + "    --list \n"
 +            + "    --read \n"
 +            + "       Syntax: --read {CONF-NAME} {CONF-NAME} [...] \n"
 +            + "    --update \n"
 +            + "       Syntax: --update {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]\n"
 +            + "    --create \n"
 +            + "       Syntax: --create {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]\n"
 +            + "    --delete \n"
 +            + "       Syntax: --delete {CONF-NAME} {CONF-NAME} [...]\n"
 +            + "    --export \n"
 +            + "       Syntax: --export {WHERE-DIR}";
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Logger service successfully created");
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        final String[] parameters = input.getParameters();
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        final ConfigurationService configurationService = SyncopeServices.get(ConfigurationService.class);
 +        switch (Options.fromName(input.getOption())) {
 +            case LIST:
 +                try {
 +                    final ConfTO confTO = configurationService.list();
 +                    System.out.println("\n - Configuration key: " + confTO.getKey());
 +                    System.out.println("");
 +                    System.out.println("Plain attributes");
 +                    for (final AttrTO attrTO : confTO.getPlainAttrMap().values()) {
 +                        System.out.println(" - Conf key: " + attrTO.getSchema());
 +                        System.out.println("    - value(s): " + attrTO.getValues());
 +                        System.out.println("    - readonly: " + attrTO.isReadonly());
 +                    }
 +                    System.out.println("");
 +                    System.out.println("Derived attributes");
 +                    for (final AttrTO attrTO : confTO.getDerAttrMap().values()) {
 +                        System.out.println(" - Conf key: " + attrTO.getSchema());
 +                        System.out.println("    - value(s): " + attrTO.getValues());
 +                        System.out.println("    - readonly: " + attrTO.isReadonly());
 +                    }
 +                    System.out.println("");
 +                    System.out.println("Virtual attributes");
 +                    for (final AttrTO attrTO : confTO.getVirAttrMap().values()) {
 +                        System.out.println(" - Conf key: " + attrTO.getSchema());
 +                        System.out.println("    - value(s): " + attrTO.getValues());
 +                        System.out.println("    - readonly: " + attrTO.isReadonly());
 +                    }
 +                    System.out.println("");
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case READ:
 +                final String readErrorMessage = "configuration --read {CONF-NAME} {CONF-NAME} [...]";
 +                if (parameters.length >= 1) {
 +                    AttrTO attrTO;
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            attrTO = configurationService.get(parameter);
 +                            System.out.println("\n - Conf key: " + attrTO.getSchema());
 +                            System.out.println("    - value(s): " + attrTO.getValues());
 +                            System.out.println("    - readonly: " + attrTO.isReadonly());
 +                            System.out.println("");
 +                        } catch (final SyncopeClientException | WebServiceException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Logger", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                            break;
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(readErrorMessage);
 +                }
 +                break;
 +            case UPDATE:
 +                final String updateErrorMessage
 +                        = "configuration --update {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]";
 +                if (parameters.length >= 1) {
 +                    Input.PairParameter pairParameter = null;
 +                    AttrTO attrTO;
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            pairParameter = input.toPairParameter(parameter);
 +                            attrTO = configurationService.get(pairParameter.getKey());
 +                            attrTO.getValues().clear();
 +                            attrTO.getValues().add(pairParameter.getValue());
 +                            configurationService.set(attrTO);
 +                            System.out.println("\n - Conf key " + attrTO.getSchema() + " updated. New value is:");
 +                            System.out.println("    - value(s): " + attrTO.getValues());
 +                            System.out.println("    - readonly: " + attrTO.isReadonly());
 +                            System.out.println("");
 +                        } catch (final IllegalArgumentException ex) {
 +                            Messages.printMessage(ex.getMessage(), updateErrorMessage);
 +                            break;
 +                        } catch (final SyncopeClientException | WebServiceException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Configuration", pairParameter.getKey());
 +                            } else if (ex.getMessage().startsWith("InvalidValues")) {
 +                                Messages.printMessage(
 +                                        pairParameter.getValue() + " is not a valid value for "
 +                                        + pairParameter.getKey());
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                            break;
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(updateErrorMessage);
 +                }
 +                break;
 +            case CREATE:
 +                final String createErrorMessage
 +                        = "configuration --create {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]";
 +                if (parameters.length >= 1) {
 +                    Input.PairParameter pairParameter = null;
 +                    AttrTO attrTO;
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            pairParameter = input.toPairParameter(parameter);
 +                            attrTO = new AttrTO();
 +                            attrTO.setSchema(pairParameter.getKey());
 +                            attrTO.getValues().add(pairParameter.getValue());
 +                            configurationService.set(attrTO);
 +                            System.out.println("\n - Conf key " + attrTO.getSchema() + " created. Value is:");
 +                            System.out.println("    - value(s): " + attrTO.getValues());
 +                            System.out.println("    - readonly: " + attrTO.isReadonly());
 +                            System.out.println("");
 +                        } catch (final IllegalArgumentException ex) {
 +                            Messages.printMessage(ex.getMessage(), createErrorMessage);
 +                            break;
 +                        } catch (final SyncopeClientException | WebServiceException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Configuration", pairParameter.getKey());
 +                                System.out.println("Create it before.");
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                            break;
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(createErrorMessage);
 +                }
 +                break;
 +            case DELETE:
 +                final String deleteErrorMessage = "configuration --delete {CONF-NAME} {CONF-NAME} [...]";
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            configurationService.delete(parameter);
 +                            Messages.printDeletedMessage("Configuration", parameter);
 +                        } catch (final SyncopeClientException | WebServiceException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Configuration", parameter);
 +                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
 +                                Messages.printMessage("You cannot delete configuration", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                            break;
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(deleteErrorMessage);
 +                }
 +                break;
 +            case EXPORT:
 +                final String exportErrorMessage = "configuration --export {WHERE-DIR}";
 +                if (parameters.length == 1) {
 +                    try {
 +                        XMLUtils.createXMLFile((SequenceInputStream) configurationService.export().getEntity(),
 +                                parameters[0] + EXPORT_FILE_NAME);
 +                        System.out.println(" - " + parameters[0] + EXPORT_FILE_NAME + " successfully created");
 +                    } catch (final IOException ex) {
 +                        Messages.printMessage(ex.getMessage());
 +                    } catch (ParserConfigurationException | SAXException | TransformerConfigurationException ex) {
 +                        LOG.error("Error creating content.xml file in {} directory", parameters[0], ex);
 +                        Messages.printMessage(
 +                                "Error creating " + parameters[0] + EXPORT_FILE_NAME + " " + ex.getMessage());
 +                        break;
 +                    } catch (final TransformerException ex) {
 +                        LOG.error("Error creating content.xml file in {} directory", parameters[0], ex);
 +                        if (ex.getCause() instanceof FileNotFoundException) {
 +                            Messages.printMessage("Permission denied on " + parameters[0]);
 +                        } else {
 +                            Messages.printMessage(
 +                                    "Error creating " + parameters[0] + EXPORT_FILE_NAME + " " + ex.getMessage());
 +                        }
 +                        break;
 +                    } catch (final SyncopeClientException ex) {
 +                        LOG.error("Error calling configuration service", ex);
 +                        Messages.printMessage("Error calling configuration service " + ex.getMessage());
 +                        break;
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(exportErrorMessage);
 +                }
 +                break;
 +            case HELP:
 +                System.out.println(HELP_MESSAGE);
 +                break;
 +            default:
 +                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
 +                break;
 +        }
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return HELP_MESSAGE;
 +    }
 +
 +    private enum Options {
 +
 +        HELP("--help"),
 +        LIST("--list"),
 +        READ("--read"),
 +        UPDATE("--update"),
 +        CREATE("--create"),
 +        DELETE("--delete"),
 +        EXPORT("--export");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +
 +        public static List<String> toList() {
 +            final List<String> options = new ArrayList<>();
 +            for (final Options value : values()) {
 +                options.add(value.getOptionName());
 +            }
 +            return options;
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
index a2a0977,0000000..3060ee1
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
@@@ -1,164 -1,0 +1,164 @@@
 +/*
 + * 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.cli.commands;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.SyncopeServices;
 +import org.apache.syncope.client.cli.messages.Messages;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.to.DomainTO;
 +import org.apache.syncope.common.rest.api.service.DomainService;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +@Command(name = "domain")
 +public class DomainCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
 +
 +    private static final String HELP_MESSAGE = "Usage: domain [options]\n"
 +            + "  Options:\n"
 +            + "    --help \n"
 +            + "    --list \n"
 +            + "    --read \n"
 +            + "       Syntax: --read {DOMAIN-KEY} {DOMAIN-KEY} [...]\n"
 +            + "    --delete \n"
 +            + "       Syntax: --delete {DOMAIN-KEY} {DOMAIN-KEY} [...]\n";
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        final String[] parameters = input.getParameters();
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        final DomainService domainService = SyncopeServices.get(DomainService.class);
 +        switch (Options.fromName(input.getOption())) {
 +            case LIST:
 +                try {
 +                    for (final DomainTO domainTO : domainService.list()) {
 +                        Messages.printMessage("Domain key: " + domainTO.getKey());
 +                    }
 +                } catch (final SyncopeClientException ex) {
 +                    Messages.printMessage("Error: " + ex.getMessage());
 +                }
 +                break;
 +            case READ:
 +                final String readErrorMessage = "domain --read {DOMAIN-KEY} {DOMAIN-KEY} [...]";
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            final DomainTO domainTO = domainService.read(parameter);
 +                            Messages.printMessage("Domain key: " + domainTO.getKey());
 +                        } catch (final SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Domain", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(readErrorMessage);
 +                }
 +                break;
 +            case DELETE:
 +                final String deleteErrorMessage = "domain --delete {DOMAIN-KEY} {DOMAIN-KEY} [...]";
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            domainService.delete(parameter);
 +                            Messages.printDeletedMessage("Domain", parameter);
 +                        } catch (final SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Domain", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(deleteErrorMessage);
 +                }
 +                break;
 +            case HELP:
 +                System.out.println(HELP_MESSAGE);
 +                break;
 +            default:
 +                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
 +        }
 +
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return HELP_MESSAGE;
 +    }
 +
 +    private enum Options {
 +
 +        HELP("--help"),
 +        LIST("--list"),
 +        READ("--read"),
 +        DELETE("--delete");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +
 +        public static List<String> toList() {
 +            final List<String> options = new ArrayList<>();
 +            for (final Options value : values()) {
 +                options.add(value.getOptionName());
 +            }
 +            return options;
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
index 85b7d73,0000000..027491a
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
@@@ -1,113 -1,0 +1,113 @@@
 +/*
 + * 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.cli.commands;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.messages.Messages;
 +import org.apache.syncope.client.cli.util.CommandUtils;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +@Command(name = "help")
 +public class HelpCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(HelpCommand.class);
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        switch (Options.fromName(input.getOption())) {
 +            case HELP:
 +                final StringBuilder generalHelpBuilder = new StringBuilder("General help\n");
 +                try {
 +                    for (final AbstractCommand command : CommandUtils.commands()) {
 +                        generalHelpBuilder.append("Command: ")
 +                                .append(command.getClass().getAnnotation(Command.class).name())
 +                                .append("\n")
 +                                .append(command.getHelpMessage())
 +                                .append("\n")
 +                                .append(" \n");
 +                    }
 +                    System.out.println(generalHelpBuilder.toString());
 +                } catch (final IllegalAccessException | IllegalArgumentException | InstantiationException e) {
 +                    Messages.printMessage(e.getMessage());
 +                }
 +                break;
 +            default:
 +                Messages.printDefaultMessage(input.getOption(), helpMessage("info", Options.toList()));
 +                break;
 +        }
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return helpMessage("help", Options.toList());
 +    }
 +
 +    private enum Options {
 +
 +        HELP("--print");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +
 +        public static List<String> toList() {
 +            final List<String> options = new ArrayList<>();
 +            for (final Options value : values()) {
 +                options.add(value.getOptionName());
 +            }
 +            return options;
 +        }
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
index 07bb952,0000000..2ab4c29
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
@@@ -1,338 -1,0 +1,338 @@@
 +/*
 + * 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.cli.commands;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.SyncopeServices;
 +import org.apache.syncope.client.cli.messages.Messages;
 +import org.apache.syncope.common.lib.to.SyncopeTO;
 +import org.apache.syncope.common.rest.api.service.SyncopeService;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +@Command(name = "info")
 +public class InfoCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(InfoCommand.class);
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        final SyncopeService syncopeService = SyncopeServices.get(SyncopeService.class);
 +        final SyncopeTO syncopeTO = syncopeService.info();
 +        switch (Options.fromName(input.getOption())) {
 +            case VERSION:
 +                try {
 +                    Messages.printMessage("Syncope version: " + syncopeTO.getVersion());
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case PWD_RESET_ALLOWED:
 +                try {
 +                    Messages.printMessage("Password reset allowed: " + syncopeTO.isPwdResetAllowed());
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case PWD_RESET_WITH_SECURITY_QUESTION:
 +                try {
 +                    Messages.printMessage("Password reset requiring security question: "
 +                            + syncopeTO.isPwdResetRequiringSecurityQuestions());
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case SELF_REG_ALLOWED:
 +                try {
 +                    Messages.printMessage("Self registration allowed: " + syncopeTO.isSelfRegAllowed());
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case PROVISIONING_MANAGER:
 +                try {
 +                    Messages.printMessage(
 +                            "Any object provisioning manager class: " + syncopeTO.getAnyObjectProvisioningManager(),
 +                            "User       provisioning manager class: " + syncopeTO.getUserProvisioningManager(),
 +                            "Group      provisioning manager class: " + syncopeTO.getGroupProvisioningManager());
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case WORKFLOW_ADAPTER:
 +                try {
 +                    Messages.printMessage(
 +                            "Any object workflow adapter class: " + syncopeTO.getAnyObjectWorkflowAdapter(),
 +                            "User       workflow adapter class: " + syncopeTO.getUserWorkflowAdapter(),
 +                            "Group      workflow adapter class: " + syncopeTO.getGroupWorkflowAdapter());
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case ACCOUNT_RULES:
 +                try {
 +                    for (final String accountRule : syncopeTO.getAccountRules()) {
 +                        Messages.printMessage("Account rule: " + accountRule);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case CONNID_LOCATION:
 +                try {
 +                    for (final String location : syncopeTO.getConnIdLocations()) {
 +                        Messages.printMessage("ConnId location: " + location);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case LOGIC_ACTIONS:
 +                try {
 +                    for (final String logic : syncopeTO.getLogicActions()) {
 +                        Messages.printMessage("Logic action: " + logic);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case MAIL_TEMPLATES:
 +                try {
 +                    for (final String template : syncopeTO.getMailTemplates()) {
 +                        Messages.printMessage("Mail template: " + template);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case MAPPING_ITEM_TRANSFORMERS:
 +                try {
 +                    for (final String tranformer : syncopeTO.getMappingItemTransformers()) {
 +                        Messages.printMessage("Mapping item tranformer: " + tranformer);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case PASSWORD_RULES:
 +                try {
 +                    for (final String rules : syncopeTO.getPasswordRules()) {
 +                        Messages.printMessage("Password rule: " + rules);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case PROPAGATION_ACTIONS:
 +                try {
 +                    for (final String action : syncopeTO.getPropagationActions()) {
 +                        Messages.printMessage("Propagation action: " + action);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case PUSH_ACTIONS:
 +                try {
 +                    for (final String action : syncopeTO.getPushActions()) {
 +                        Messages.printMessage("Push action: " + action);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case PUSH_CORRELATION_ACTIONS:
 +                try {
 +                    for (final String rule : syncopeTO.getPushCorrelationRules()) {
 +                        Messages.printMessage("Push correlation rule: " + rule);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case REPORTLETS:
 +                try {
 +                    for (final String reportlet : syncopeTO.getReportlets()) {
 +                        Messages.printMessage("Reportlet: " + reportlet);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case SYNC_ACTIONS:
 +                try {
 +                    for (final String action : syncopeTO.getSyncActions()) {
 +                        Messages.printMessage("Sync action: " + action);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case SYNC_CORRELATION_RULES:
 +                try {
 +                    for (final String rule : syncopeTO.getSyncCorrelationRules()) {
 +                        Messages.printMessage("Sync correlation rule: " + rule);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case TASK_JOBS:
 +                try {
 +                    for (final String job : syncopeTO.getTaskJobs()) {
 +                        Messages.printMessage("Task job: " + job);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case VALIDATORS:
 +                try {
 +                    for (final String validator : syncopeTO.getValidators()) {
 +                        Messages.printMessage("Validator: " + validator);
 +                    }
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case PASSWORD_GENERATOR:
 +                try {
 +                    Messages.printMessage(
 +                            "Password generator class: " + syncopeTO.getPasswordGenerator());
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case VIR_ATTR_CACHE:
 +                try {
 +                    Messages.printMessage(
 +                            "Virtual attribute cache class: " + syncopeTO.getVirAttrCache());
 +                } catch (final Exception ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                    break;
 +                }
 +                break;
 +            case HELP:
 +                System.out.println(helpMessage("info", Options.toList()));
 +                break;
 +            default:
 +                Messages.printDefaultMessage(input.getOption(), helpMessage("info", Options.toList()));
 +                break;
 +        }
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return helpMessage("info", Options.toList());
 +    }
 +
 +    private enum Options {
 +
 +        VERSION("--version"),
 +        PWD_RESET_ALLOWED("--pwd-reset-allowed"),
 +        PWD_RESET_WITH_SECURITY_QUESTION("--pwd-reset-with-question"),
 +        SELF_REG_ALLOWED("--self-reg-allowed"),
 +        PROVISIONING_MANAGER("--provisioning-manager-classes"),
 +        WORKFLOW_ADAPTER("--workflow-adapter-classes"),
 +        ACCOUNT_RULES("--account-rules-classes"),
 +        CONNID_LOCATION("--connid-locations"),
 +        LOGIC_ACTIONS("--logic-actions"),
 +        MAIL_TEMPLATES("--mail-templates"),
 +        MAPPING_ITEM_TRANSFORMERS("--mapping-item-transformers"),
 +        PASSWORD_RULES("--password-rules"),
 +        PROPAGATION_ACTIONS("--propagation-actions"),
 +        PUSH_ACTIONS("--push-actions"),
 +        PUSH_CORRELATION_ACTIONS("--push-correlation-actions"),
 +        REPORTLETS("--reportlets"),
 +        SYNC_ACTIONS("--sync-actions"),
 +        SYNC_CORRELATION_RULES("--sync-correlation-rules"),
 +        TASK_JOBS("--task-jobs"),
 +        VALIDATORS("--validators"),
 +        PASSWORD_GENERATOR("--password-generator"),
 +        VIR_ATTR_CACHE("--vir-attr-cache"),
 +        HELP("--help");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +
 +        public static List<String> toList() {
 +            final List<String> options = new ArrayList<>();
 +            for (final Options value : values()) {
 +                options.add(value.getOptionName());
 +            }
 +            return options;
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
index 6c11c6f,0000000..360c16b
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
@@@ -1,267 -1,0 +1,267 @@@
 +/*
 + * 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.cli.commands;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import javax.xml.ws.WebServiceException;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.SyncopeServices;
 +import org.apache.syncope.client.cli.messages.Messages;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.to.LoggerTO;
 +import org.apache.syncope.common.lib.types.LoggerLevel;
 +import org.apache.syncope.common.lib.types.LoggerType;
 +import org.apache.syncope.common.rest.api.service.LoggerService;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +@Command(name = "logger")
 +public class LoggerCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
 +
 +    private static final String HELP_MESSAGE = "Usage: logger [options]\n"
 +            + "  Options:\n"
 +            + "    --help \n"
 +            + "    --list \n"
 +            + "    --read \n"
 +            + "       Syntax: --read {LOG-NAME} {LOG-NAME} [...]\n"
 +            + "    --update \n"
 +            + "       Syntax: --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]\n"
 +            + "    --update-all \n"
 +            + "       Syntax: --update-all {LOG-LEVEL} \n"
 +            + "    --create \n"
 +            + "       Syntax: --create {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]\n"
 +            + "    --delete \n"
 +            + "       Syntax: --delete {LOG-NAME} {LOG-NAME} [...]";
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        final String[] parameters = input.getParameters();
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        final LoggerService loggerService = SyncopeServices.get(LoggerService.class);
 +        switch (Options.fromName(input.getOption())) {
 +            case LIST:
 +                try {
 +                    for (final LoggerTO loggerTO : loggerService.list(LoggerType.LOG)) {
 +                        System.out.println(" - " + loggerTO.getKey() + " -> " + loggerTO.getLevel());
 +                        System.out.println("");
 +                    }
 +                } catch (final SyncopeClientException ex) {
 +                    Messages.printMessage("Error: " + ex.getMessage());
 +                }
 +                break;
 +            case READ:
 +                final String readErrorMessage = "logger --read {LOG-NAME} {LOG-NAME} [...]";
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            final LoggerTO loggerTO = loggerService.read(LoggerType.LOG, parameter);
 +                            System.out.println("\n - Logger");
 +                            System.out.println("   - key: " + loggerTO.getKey());
 +                            System.out.println("   - level: " + loggerTO.getLevel());
 +                            System.out.println("");
 +                        } catch (final SyncopeClientException | WebServiceException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Logger", parameter);
 +                            } else {
 +                                Messages.printMessage("Error: " + ex.getMessage());
 +                            }
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(readErrorMessage);
 +                }
 +                break;
 +            case UPDATE:
 +                final String updateErrorMessage = "logger --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    Input.PairParameter pairParameter;
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            pairParameter = input.toPairParameter(parameter);
 +                            final LoggerTO loggerTO = loggerService.read(LoggerType.LOG, pairParameter.getKey());
 +                            loggerTO.setLevel(LoggerLevel.valueOf(pairParameter.getValue()));
 +                            loggerService.update(LoggerType.LOG, loggerTO);
 +                            System.out.
 +                                    println("\n - Logger " + loggerTO.getKey() + " updated");
 +                            System.out.println("   - new level: " + loggerTO.getLevel());
 +                            System.out.println("");
 +                        } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
 +                            if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
 +                                Messages.printTypeNotValidMessage(
 +                                        "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
 +                            } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
 +                                Messages.printMessage(ex.getMessage(), updateErrorMessage);
 +                            } else if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Logger", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage(), updateErrorMessage);
 +                            }
 +                            break;
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(updateErrorMessage);
 +                }
 +                break;
 +            case UPDATE_ALL:
 +                final String updateAllErrorMessage = "logger --update-all {LOG-LEVEL}";
 +
 +                if (parameters.length == 1) {
 +                    for (final LoggerTO loggerTO : loggerService.list(LoggerType.LOG)) {
 +                        try {
 +                            loggerTO.setLevel(LoggerLevel.valueOf(parameters[0]));
 +                            loggerService.update(LoggerType.LOG, loggerTO);
 +                            System.out.
 +                                    println("\n - Logger " + loggerTO.getKey() + " updated");
 +                            System.out.println("   - new level: " + loggerTO.getLevel());
 +                            System.out.println("");
 +                        } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
 +                            if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
 +                                Messages.printTypeNotValidMessage(
 +                                        "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
 +                            } else {
 +                                Messages.printMessage(ex.getMessage(), updateAllErrorMessage);
 +                            }
 +                            break;
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(updateAllErrorMessage);
 +                }
 +                break;
 +            case CREATE:
 +                final String createErrorMessage = "logger --create {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    Input.PairParameter pairParameter;
 +                    LoggerTO loggerTO;
 +                    for (final String parameter : parameters) {
 +                        loggerTO = new LoggerTO();
 +                        try {
 +                            pairParameter = input.toPairParameter(parameter);
 +                            loggerTO.setKey(pairParameter.getKey());
 +                            loggerTO.setLevel(LoggerLevel.valueOf(pairParameter.getValue()));
 +                            loggerService.update(LoggerType.LOG, loggerTO);
 +                            System.out.
 +                                    println("\n - Logger " + loggerTO.getKey() + " updated");
 +                            System.out.println("   - level: " + loggerTO.getLevel());
 +                            System.out.println("");
 +                        } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
 +                            Messages.printTypeNotValidMessage(
 +                                    "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
 +                            break;
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(createErrorMessage);
 +                }
 +                break;
 +            case DELETE:
 +                final String deleteErrorMessage = "logger --delete {LOG-NAME} {LOG-NAME} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            loggerService.delete(LoggerType.LOG, parameter);
 +                            Messages.printDeletedMessage("Logger", parameter);
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Logger", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(deleteErrorMessage);
 +                }
 +                break;
 +            case HELP:
 +                System.out.println(HELP_MESSAGE);
 +                break;
 +            default:
 +                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
 +        }
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return HELP_MESSAGE;
 +    }
 +
 +    private enum Options {
 +
 +        HELP("--help"),
 +        LIST("--list"),
 +        READ("--read"),
 +        UPDATE("--update"),
 +        UPDATE_ALL("--update-all"),
 +        CREATE("--create"),
 +        DELETE("--delete");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +
 +        public static List<String> toList() {
 +            final List<String> options = new ArrayList<>();
 +            for (final Options value : values()) {
 +                options.add(value.getOptionName());
 +            }
 +            return options;
 +        }
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
index 194ee11,0000000..28ae8c5
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/NotificationCommand.java
@@@ -1,169 -1,0 +1,169 @@@
 +/*
 + * 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.cli.commands;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import javax.xml.ws.WebServiceException;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.SyncopeServices;
 +import org.apache.syncope.client.cli.messages.Messages;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.to.NotificationTO;
 +import org.apache.syncope.common.rest.api.service.NotificationService;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +@Command(name = "notification")
 +public class NotificationCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(NotificationCommand.class);
 +
 +    private static final String HELP_MESSAGE = "Usage: notification [options]\n"
 +            + "  Options:\n"
 +            + "    --help \n"
 +            + "    --list \n"
 +            + "    --read \n"
 +            + "       Syntax: --read {NOTIFICATION-ID} \n"
 +            + "    --delete \n"
 +            + "       Syntax: --delete {NOTIFICATION-ID}";
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        final String[] parameters = input.getParameters();
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        final NotificationService notificationService = SyncopeServices.get(NotificationService.class);
 +        switch (Options.fromName(input.getOption())) {
 +            case LIST:
 +                try {
 +                    for (final NotificationTO notificationTO : notificationService.list()) {
 +                        System.out.println(notificationTO);
 +                    }
 +                } catch (final SyncopeClientException ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                }
 +                break;
 +            case READ:
 +                final String readErrorMessage = "notification --read {NOTIFICATION-ID} {NOTIFICATION-ID} [...]";
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            System.out.println(notificationService.read(Long.valueOf(parameter)));
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("notification", parameter);
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Notification", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(readErrorMessage);
 +                }
 +                break;
 +            case DELETE:
 +                final String deleteErrorMessage = "notification --delete {NOTIFICATION-ID} {NOTIFICATION-ID} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            notificationService.delete(Long.valueOf(parameter));
 +                            Messages.printDeletedMessage("Notification", parameter);
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Notification", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("notification", parameter);
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(deleteErrorMessage);
 +                }
 +                break;
 +            case HELP:
 +                System.out.println(HELP_MESSAGE);
 +                break;
 +            default:
 +                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
 +        }
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return HELP_MESSAGE;
 +    }
 +
 +    private enum Options {
 +
 +        HELP("--help"),
 +        LIST("--list"),
 +        READ("--read"),
 +        DELETE("--delete");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +
 +        public static List<String> toList() {
 +            final List<String> options = new ArrayList<>();
 +            for (final Options value : values()) {
 +                options.add(value.getOptionName());
 +            }
 +            return options;
 +        }
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
index a69be18,0000000..a5017cf
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
@@@ -1,186 -1,0 +1,186 @@@
 +/*
 + * 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.cli.commands;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import javax.xml.ws.WebServiceException;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.SyncopeServices;
 +import org.apache.syncope.client.cli.messages.Messages;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
 +import org.apache.syncope.common.lib.types.PolicyType;
 +import org.apache.syncope.common.rest.api.service.PolicyService;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +@Command(name = "policy")
 +public class PolicyCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(PolicyCommand.class);
 +
 +    private static final String HELP_MESSAGE = "Usage: policy [options]\n"
 +            + "  Options:\n"
 +            + "    --help \n"
 +            + "    --list-policy \n"
 +            + "       Syntax: --list-policy {POLICY-TYPE} \n"
 +            + "          Policy type: ACCOUNT / PASSWORD / SYNC / PUSH\n"
 +            + "    --read \n"
 +            + "       Syntax: --read {POLICY-ID} {POLICY-ID} [...]\n"
 +            + "    --delete \n"
 +            + "       Syntax: --delete {POLICY-ID} {POLICY-ID} [...]";
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        final String[] parameters = input.getParameters();
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        final PolicyService policyService = SyncopeServices.get(PolicyService.class);
 +        switch (Options.fromName(input.getOption())) {
 +            case LIST_POLICY:
 +                final String listPolicyErrorMessage = "policy --list-policy {POLICY-TYPE}\n"
 +                        + "   Policy type: ACCOUNT / PASSWORD / SYNC / PUSH";
 +
 +                if (parameters.length == 1) {
 +                    try {
 +                        for (final AbstractPolicyTO policyTO : policyService.list(PolicyType.valueOf(parameters[0]))) {
 +                            System.out.println(policyTO);
 +                        }
 +                    } catch (final SyncopeClientException ex) {
 +                        Messages.printMessage(ex.getMessage());
 +                    } catch (final IllegalArgumentException ex) {
 +                        Messages.printTypeNotValidMessage(
 +                                "policy", input.firstParameter(), fromEnumToArray(PolicyType.class));
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(listPolicyErrorMessage);
 +                }
 +                break;
 +            case READ:
 +                final String readErrorMessage = "policy --read {POLICY-ID} {POLICY-ID} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            System.out.println(policyService.read(Long.valueOf(parameter)));
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("policy", parameter);
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Policy", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(readErrorMessage);
 +                }
 +                break;
 +            case DELETE:
 +                final String deleteErrorMessage = "policy --delete {POLICY-ID} {POLICY-ID} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            policyService.delete(Long.valueOf(parameter));
 +                            Messages.printDeletedMessage("Policy", parameter);
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            System.out.println("Error:");
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Policy", parameter);
 +                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
 +                                Messages.printMessage("You cannot delete policy " + parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("policy", parameter);
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(deleteErrorMessage);
 +                }
 +                break;
 +            case HELP:
 +                System.out.println(HELP_MESSAGE);
 +                break;
 +            default:
 +                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
 +        }
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return HELP_MESSAGE;
 +    }
 +
 +    private enum Options {
 +
 +        HELP("--help"),
 +        LIST_POLICY("--list-policy"),
 +        READ("--read"),
 +        DELETE("--delete");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +
 +        public static List<String> toList() {
 +            final List<String> options = new ArrayList<>();
 +            for (final Options value : values()) {
 +                options.add(value.getOptionName());
 +            }
 +            return options;
 +        }
 +    }
 +
 +}


[54/54] [abbrv] syncope git commit: merge from master

Posted by fm...@apache.org.
merge from master


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

Branch: refs/heads/SYNCOPE-156
Commit: 973cd50fe5c8852c6ba087fbbd984e54931ece94
Parents: 13f96e0 73f73f2
Author: fmartelli <fa...@gmail.com>
Authored: Fri Oct 23 12:28:09 2015 +0200
Committer: fmartelli <fa...@gmail.com>
Committed: Fri Oct 23 12:28:09 2015 +0200

----------------------------------------------------------------------
 client/cli/pom.xml                              |  15 +-
 .../apache/syncope/client/cli/ArgsManager.java  |  50 +++
 .../syncope/client/cli/AvailableServices.java   |  31 ++
 .../org/apache/syncope/client/cli/Command.java  |  32 ++
 .../syncope/client/cli/CommandClassScanner.java |  29 ++
 .../client/cli/ComponentClassScanner.java       |  44 ++
 .../org/apache/syncope/client/cli/Input.java    | 111 +++++
 .../syncope/client/cli/ResultManager.java       |  25 ++
 .../apache/syncope/client/cli/SyncopeAdm.java   | 116 ++---
 .../syncope/client/cli/SyncopeServices.java     |  32 +-
 .../client/cli/commands/AbstractCommand.java    |  10 +-
 .../cli/commands/CommonsResultManager.java      |  52 +++
 .../cli/commands/ConfigurationCommand.java      | 209 ---------
 .../client/cli/commands/LoggerCommand.java      | 168 -------
 .../cli/commands/NotificationCommand.java       |  92 ----
 .../client/cli/commands/PolicyCommand.java      | 105 -----
 .../client/cli/commands/ReportCommand.java      | 433 +++++++++++++------
 .../AbstractConfigurationCommand.java           |  30 ++
 .../configuration/ConfigurationCommand.java     | 120 +++++
 .../configuration/ConfigurationDelete.java      |  57 +++
 .../configuration/ConfigurationExport.java      |  71 +++
 .../configuration/ConfigurationGet.java         |  36 ++
 .../configuration/ConfigurationRead.java        |  62 +++
 .../ConfigurationResultManager.java             |  53 +++
 .../configuration/ConfigurationUpdate.java      |  76 ++++
 .../commands/domain/AbstractDomainCommand.java  |  30 ++
 .../cli/commands/domain/DomainCommand.java      | 101 +++++
 .../cli/commands/domain/DomainDelete.java       |  53 +++
 .../client/cli/commands/domain/DomainList.java  |  38 ++
 .../client/cli/commands/domain/DomainRead.java  |  53 +++
 .../commands/domain/DomainResultManager.java    |  25 ++
 .../syncope/client/cli/commands/help/Help.java  |  43 ++
 .../client/cli/commands/help/HelpCommand.java   |  90 ++++
 .../cli/commands/help/HelpResultManager.java    |  25 ++
 .../syncope/client/cli/commands/info/Info.java  | 243 +++++++++++
 .../client/cli/commands/info/InfoCommand.java   | 180 ++++++++
 .../cli/commands/info/InfoResultManager.java    |  25 ++
 .../cli/commands/install/InstallCommand.java    |  87 ++++
 .../install/InstallConfigFileTemplate.java      |  57 +++
 .../commands/install/InstallResultManager.java  |  90 ++++
 .../cli/commands/install/InstallSetup.java      | 182 ++++++++
 .../commands/logger/AbstractLoggerCommand.java  |  30 ++
 .../cli/commands/logger/LoggerCommand.java      | 127 ++++++
 .../cli/commands/logger/LoggerCreate.java       |  70 +++
 .../cli/commands/logger/LoggerDelete.java       |  55 +++
 .../client/cli/commands/logger/LoggerList.java  |  37 ++
 .../client/cli/commands/logger/LoggerRead.java  |  62 +++
 .../commands/logger/LoggerResultManager.java    |  61 +++
 .../cli/commands/logger/LoggerUpdate.java       |  78 ++++
 .../cli/commands/logger/LoggerUpdateAll.java    |  69 +++
 .../AbstractNotificationCommand.java            |  30 ++
 .../notification/NotificationCommand.java       | 109 +++++
 .../notification/NotificationDelete.java        |  56 +++
 .../commands/notification/NotificationList.java |  35 ++
 .../commands/notification/NotificationRead.java |  54 +++
 .../notification/NotificationResultManager.java |  25 ++
 .../commands/policy/AbstractPolicyCommand.java  |  30 ++
 .../cli/commands/policy/PolicyCommand.java      | 111 +++++
 .../cli/commands/policy/PolicyDelete.java       |  59 +++
 .../client/cli/commands/policy/PolicyList.java  |  59 +++
 .../client/cli/commands/policy/PolicyRead.java  |  58 +++
 .../commands/policy/PolicyResultManager.java    | 120 +++++
 .../commands/schema/AbstractSchemaCommand.java  |  30 ++
 .../cli/commands/schema/SchemaCommand.java      | 127 ++++++
 .../cli/commands/schema/SchemaDelete.java       |  64 +++
 .../client/cli/commands/schema/SchemaList.java  |  70 +++
 .../cli/commands/schema/SchemaListAll.java      |  55 +++
 .../cli/commands/schema/SchemaListDerived.java  |  40 ++
 .../cli/commands/schema/SchemaListPlain.java    |  40 ++
 .../cli/commands/schema/SchemaListVirtual.java  |  40 ++
 .../client/cli/commands/schema/SchemaRead.java  |  78 ++++
 .../commands/schema/SchemaResultManager.java    |  96 ++++
 .../cli/commands/task/AbstractTaskCommand.java  |  30 ++
 .../client/cli/commands/task/TaskCommand.java   | 140 ++++++
 .../client/cli/commands/task/TaskDelete.java    |  58 +++
 .../client/cli/commands/task/TaskExecute.java   |  66 +++
 .../cli/commands/task/TaskExecutionDelete.java  |  58 +++
 .../cli/commands/task/TaskExecutionRead.java    |  58 +++
 .../client/cli/commands/task/TaskList.java      |  59 +++
 .../client/cli/commands/task/TaskRead.java      |  60 +++
 .../cli/commands/task/TaskResultManager.java    | 222 ++++++++++
 .../cli/commands/task/TaskRunningJobs.java      |  34 ++
 .../cli/commands/task/TaskScheduledJobs.java    |  34 ++
 .../syncope/client/cli/messages/Messages.java   |  94 ++++
 .../syncope/client/cli/messages/Table.java      | 194 +++++++++
 .../client/cli/messages/TwoColumnTable.java     | 262 +++++++++++
 .../syncope/client/cli/util/CommandUtils.java   |  92 ++++
 .../client/cli/util/FileSystemUtils.java        |  48 ++
 .../syncope/client/cli/util/JasyptUtils.java    |  49 +++
 .../cli/validators/DebugLevelValidator.java     |  60 ---
 .../src/main/resources/configuration.properties |  18 +
 client/cli/src/main/resources/log4j2.xml        |  24 +-
 .../cli/src/main/resources/syncope.properties   |  19 -
 .../client/console/SyncopeConsoleSession.java   |   4 +-
 .../commons/SortableAnyProviderComparator.java  |   2 +-
 .../client/console/commons/status/Status.java   |   2 +-
 .../syncope/client/console/pages/Login.java     |   4 +-
 .../console/pages/ProvisioningModalPage.java    |   2 +-
 .../client/console/pages/StatusModalPage.java   |   2 +-
 .../console/panels/AbstractResourceModal.java   |   2 +-
 .../console/panels/ResourceSecurityPanel.java   |   2 +-
 .../console/rest/ConfigurationRestClient.java   |  15 +-
 .../client/console/topology/Topology.java       |   2 +-
 .../console/topology/WebSocketBehavior.java     |   4 +-
 .../wicket/markup/html/form/ActionLink.java     |   2 +-
 .../provision/ProvisionWizardBuilder.java       |   6 +-
 .../client/lib/RestClientFactoryBean.java       |  34 +-
 .../syncope/client/lib/SyncopeClient.java       |  12 +-
 .../client/lib/SyncopeClientFactoryBean.java    |  37 +-
 client/old_console/pom.xml                      |   1 +
 .../syncope/common/lib/AnyOperations.java       |  26 +-
 .../syncope/common/lib/patch/AnyPatch.java      |   5 +-
 .../org/apache/syncope/common/lib/to/AnyTO.java |   5 +-
 .../apache/syncope/common/lib/to/ConfTO.java    |  30 --
 .../apache/syncope/common/lib/to/MappingTO.java |   9 +
 .../syncope/common/lib/to/ProvisionTO.java      |  18 +
 .../syncope/common/lib/to/VirSchemaTO.java      |  20 +
 .../syncope/common/lib/types/AnyTypeKind.java   |   2 +-
 .../common/lib/types/ClientExceptionType.java   |   2 +-
 .../syncope/common/lib/types/Entitlement.java   |   4 +
 .../common/lib/types/IntMappingType.java        |   2 +-
 .../common/lib/types/PropagationByResource.java |  11 +
 .../syncope/common/lib/types/TaskType.java      |   4 +-
 common/rest-api/pom.xml                         |  17 +-
 .../syncope/common/rest/api/Preference.java     |   2 +-
 .../common/rest/api/service/AnyService.java     |  22 +-
 .../rest/api/service/AnyTypeClassService.java   |   2 +-
 .../common/rest/api/service/AnyTypeService.java |   2 +-
 .../rest/api/service/ConfigurationService.java  |   4 +-
 .../rest/api/service/ConnectorService.java      |   4 +-
 .../common/rest/api/service/DomainService.java  |   2 +-
 .../common/rest/api/service/GroupService.java   |   2 +-
 .../common/rest/api/service/LoggerService.java  |   2 +-
 .../rest/api/service/NotificationService.java   |   2 +-
 .../common/rest/api/service/PolicyService.java  |  11 +-
 .../common/rest/api/service/RealmService.java   |   2 +-
 .../api/service/RelationshipTypeService.java    |   2 +-
 .../common/rest/api/service/ReportService.java  |   2 +-
 .../rest/api/service/ResourceService.java       |   4 +-
 .../common/rest/api/service/RoleService.java    |   2 +-
 .../common/rest/api/service/SchemaService.java  |  14 +-
 .../api/service/SecurityQuestionService.java    |   2 +-
 .../common/rest/api/service/SyncopeService.java |   3 +
 .../common/rest/api/service/TaskService.java    |   5 +-
 .../rest/api/service/UserSelfService.java       |  14 +-
 .../common/rest/api/service/UserService.java    |  12 +-
 .../rest/api/service/WorkflowService.java       |   2 +-
 .../syncope/core/logic/AbstractAnyLogic.java    |   2 +-
 .../syncope/core/logic/AnyObjectLogic.java      |  12 -
 .../syncope/core/logic/ConfigurationLogic.java  |  16 +-
 .../apache/syncope/core/logic/GroupLogic.java   |  12 -
 .../apache/syncope/core/logic/LoggerLogic.java  |  26 ++
 .../apache/syncope/core/logic/PolicyLogic.java  |  30 +-
 .../syncope/core/logic/ResourceLogic.java       |  36 +-
 .../apache/syncope/core/logic/UserLogic.java    |  41 +-
 .../syncope/core/logic/init/LoggerLoader.java   |   2 +-
 .../core/logic/report/StaticReportlet.java      |   4 +-
 .../core/logic/report/UserReportlet.java        |   8 +-
 .../apache/syncope/core/misc/DataFormat.java    | 117 -----
 .../apache/syncope/core/misc/FormatUtils.java   | 117 +++++
 .../apache/syncope/core/misc/MappingUtils.java  | 172 +++-----
 .../core/misc/jexl/ClassFreeUberspectImpl.java  |   2 +-
 .../syncope/core/misc/jexl/JexlUtils.java       |  35 +-
 .../core/misc/security/AuthDataAccessor.java    |  10 +-
 .../security/SyncopeAuthenticationProvider.java |   6 +-
 .../persistence/api/ImplementationLookup.java   |   2 +-
 .../core/persistence/api/dao/AnyDAO.java        |   2 +-
 .../core/persistence/api/dao/AnySearchDAO.java  |  10 +-
 .../api/dao/ExternalResourceDAO.java            |   5 +-
 .../core/persistence/api/dao/VirAttrDAO.java    |  35 --
 .../core/persistence/api/dao/VirSchemaDAO.java  |   8 +-
 .../core/persistence/api/entity/Any.java        |  10 +-
 .../core/persistence/api/entity/AnyUtils.java   |   6 +-
 .../persistence/api/entity/AnyUtilsFactory.java |   2 +-
 .../core/persistence/api/entity/Attr.java       |   2 +-
 .../core/persistence/api/entity/DerAttr.java    |   2 +-
 .../api/entity/DynGroupMembership.java          |   2 +-
 .../persistence/api/entity/DynMembership.java   |   2 +-
 .../api/entity/LinkingMappingItem.java          | 140 ++++++
 .../core/persistence/api/entity/Membership.java |   2 +-
 .../core/persistence/api/entity/PlainAttr.java  |   2 +-
 .../persistence/api/entity/Relationship.java    |   2 +-
 .../core/persistence/api/entity/VirAttr.java    |  30 --
 .../core/persistence/api/entity/VirSchema.java  |  13 +
 .../api/entity/anyobject/AVirAttr.java          |  25 --
 .../api/entity/anyobject/AnyObject.java         |   2 +-
 .../core/persistence/api/entity/conf/Conf.java  |   3 +-
 .../persistence/api/entity/group/GVirAttr.java  |  25 --
 .../persistence/api/entity/group/Group.java     |  14 +-
 .../api/entity/task/PropagationTask.java        |   4 +
 .../persistence/api/entity/user/UVirAttr.java   |  25 --
 .../core/persistence/api/entity/user/User.java  |  14 +-
 .../jpa/content/ContentLoaderHandler.java       |   6 +-
 .../jpa/content/MultiParentNode.java            |   2 +-
 .../jpa/content/XMLContentExporter.java         |  10 +-
 .../persistence/jpa/dao/AbstractAnyDAO.java     |  11 +-
 .../persistence/jpa/dao/JPAAnySearchDAO.java    |  12 +-
 .../core/persistence/jpa/dao/JPAConfDAO.java    |  28 +-
 .../core/persistence/jpa/dao/JPADerAttrDAO.java |   2 +-
 .../jpa/dao/JPAExternalResourceDAO.java         |  29 +-
 .../core/persistence/jpa/dao/JPAGroupDAO.java   |   2 +-
 .../persistence/jpa/dao/JPAPlainAttrDAO.java    |   2 +-
 .../jpa/dao/JPAPlainAttrValueDAO.java           |   7 +-
 .../core/persistence/jpa/dao/JPAVirAttrDAO.java |  86 ----
 .../persistence/jpa/dao/JPAVirSchemaDAO.java    |  35 +-
 .../core/persistence/jpa/dao/SearchSupport.java |   2 +-
 .../persistence/jpa/entity/AbstractAny.java     |  17 +-
 .../persistence/jpa/entity/AbstractAttr.java    |   2 +-
 .../persistence/jpa/entity/AbstractDerAttr.java |   2 +-
 .../jpa/entity/AbstractDynMembership.java       |   2 +-
 .../persistence/jpa/entity/AbstractExec.java    |   4 +-
 .../jpa/entity/AbstractPlainAttr.java           |   2 +-
 .../jpa/entity/AbstractPlainAttrValue.java      |  18 +-
 .../persistence/jpa/entity/AbstractVirAttr.java |  71 ---
 .../jpa/entity/AnnotatedEntityListener.java     |   4 +-
 .../persistence/jpa/entity/JPAAnyUtils.java     |  52 +--
 .../jpa/entity/JPAAnyUtilsFactory.java          |   2 +-
 .../persistence/jpa/entity/JPAConnInstance.java |   9 +-
 .../persistence/jpa/entity/JPADerSchema.java    |   4 +-
 .../jpa/entity/JPAEntityFactory.java            |   8 -
 .../persistence/jpa/entity/JPANotification.java |   4 +-
 .../persistence/jpa/entity/JPAPlainSchema.java  |   5 +-
 .../persistence/jpa/entity/JPAVirSchema.java    |  40 ++
 .../anyobject/JPAAPlainAttrUniqueValue.java     |   2 +-
 .../entity/anyobject/JPAAPlainAttrValue.java    |   2 +-
 .../jpa/entity/anyobject/JPAAVirAttr.java       |  59 ---
 .../jpa/entity/anyobject/JPAAnyObject.java      |  24 +-
 .../entity/conf/JPACPlainAttrUniqueValue.java   |   2 +-
 .../jpa/entity/conf/JPACPlainAttrValue.java     |   2 +-
 .../persistence/jpa/entity/conf/JPAConf.java    |  21 -
 .../entity/group/JPAGPlainAttrUniqueValue.java  |   2 +-
 .../jpa/entity/group/JPAGPlainAttrValue.java    |   2 +-
 .../jpa/entity/group/JPAGVirAttr.java           |  59 ---
 .../persistence/jpa/entity/group/JPAGroup.java  |  24 +-
 .../entity/resource/JPAExternalResource.java    |  16 +-
 .../jpa/entity/resource/JPAMapping.java         |  27 +-
 .../jpa/entity/resource/JPAMappingItem.java     |  11 +-
 .../jpa/entity/resource/JPAProvision.java       |   1 -
 .../jpa/entity/task/JPAPropagationTask.java     |  12 +
 .../entity/user/JPAUPlainAttrUniqueValue.java   |   2 +-
 .../jpa/entity/user/JPAUPlainAttrValue.java     |   2 +-
 .../jpa/entity/user/JPAUVirAttr.java            |  59 ---
 .../persistence/jpa/entity/user/JPAUser.java    |  24 +-
 .../entity/ExternalResourceValidator.java       |  77 +++-
 .../jpa/validation/entity/PlainAttrCheck.java   |   2 +-
 .../validation/entity/PlainAttrValidator.java   |   2 +-
 .../resources/META-INF/spring-orm-oracle.xml    |  25 --
 .../resources/META-INF/spring-orm-sqlserver.xml |  25 --
 .../src/main/resources/META-INF/spring-orm.xml  |  25 --
 .../main/resources/domains/MasterContent.xml    |   6 +
 .../src/main/resources/indexes.xml              |   4 -
 .../persistence/jpa/inner/AnyObjectTest.java    |   5 +
 .../persistence/jpa/inner/MultitenancyTest.java |   2 +-
 .../persistence/jpa/inner/PlainAttrTest.java    |   1 -
 .../persistence/jpa/inner/PlainSchemaTest.java  |   2 +-
 .../persistence/jpa/inner/ResourceTest.java     |  46 ++
 .../core/persistence/jpa/inner/TaskTest.java    |   1 +
 .../core/persistence/jpa/inner/VirAttrTest.java | 118 -----
 .../persistence/jpa/inner/VirSchemaTest.java    |  24 +-
 .../persistence/jpa/outer/ResourceTest.java     |  15 +-
 .../core/persistence/jpa/outer/TaskTest.java    |   1 +
 .../persistence/jpa/outer/VirSchemaTest.java    |  76 ++++
 .../test/resources/domains/MasterContent.xml    |  37 +-
 .../src/test/resources/domains/TwoContent.xml   |   6 +
 .../core/provisioning/api/Connector.java        |  27 +-
 .../core/provisioning/api/VirAttrHandler.java   |  52 +--
 .../api/cache/VirAttrCacheValue.java            |  36 +-
 .../api/data/ConfigurationDataBinder.java       |   4 +-
 .../provisioning/api/data/UserDataBinder.java   |   2 +
 .../api/propagation/PropagationManager.java     |   5 +-
 .../core/provisioning/api/sync/PushActions.java |  20 +-
 .../provisioning/java/ConnectorFacadeProxy.java |  29 +-
 .../DefaultAnyObjectProvisioningManager.java    |  18 -
 .../java/DefaultGroupProvisioningManager.java   |  18 -
 .../java/DefaultUserProvisioningManager.java    |  46 +-
 .../provisioning/java/VirAttrHandlerImpl.java   | 356 +++------------
 .../java/data/AbstractAnyDataBinder.java        | 138 +++---
 .../java/data/AnyObjectDataBinderImpl.java      |  11 +-
 .../java/data/ConfigurationDataBinderImpl.java  |  21 +-
 .../java/data/GroupDataBinderImpl.java          |  11 +-
 .../java/data/ResourceDataBinderImpl.java       |  60 ++-
 .../java/data/SchemaDataBinderImpl.java         |  34 +-
 .../java/data/UserDataBinderImpl.java           |  33 +-
 .../core/provisioning/java/job/TaskJob.java     |   4 +-
 .../notification/NotificationManagerImpl.java   |  26 +-
 .../AbstractPropagationTaskExecutor.java        |  89 ++--
 .../propagation/PropagationManagerImpl.java     | 254 +++++------
 .../java/sync/AbstractPushResultHandler.java    |  57 +--
 .../java/sync/AbstractSyncResultHandler.java    |  42 +-
 .../java/sync/AbstractSyncopeResultHandler.java |   2 +-
 .../sync/AnyObjectPushResultHandlerImpl.java    |   4 +-
 .../sync/AnyObjectSyncResultHandlerImpl.java    |   2 +-
 .../java/sync/DefaultPushActions.java           |  16 +-
 .../java/sync/GroupPushResultHandlerImpl.java   |   4 +-
 .../java/sync/GroupSyncResultHandlerImpl.java   |   2 +-
 .../provisioning/java/sync/PushJobDelegate.java |   4 +-
 .../provisioning/java/sync/SyncJobDelegate.java |  31 +-
 .../core/provisioning/java/sync/SyncUtils.java  |  12 +-
 .../java/sync/UserPushResultHandlerImpl.java    |   6 +-
 .../java/sync/UserSyncResultHandlerImpl.java    |   2 +-
 core/rest-cxf/pom.xml                           | 311 +++++++------
 .../rest/cxf/ThreadLocalCleanupListener.java    |   4 +-
 .../syncope/core/rest/cxf/WADLServlet.java      | 118 +++++
 .../rest/cxf/service/AbstractAnyService.java    |   9 +-
 .../cxf/service/ConfigurationServiceImpl.java   |   4 +-
 .../rest/cxf/service/LoggerServiceImpl.java     |  16 +-
 .../rest/cxf/service/PolicyServiceImpl.java     |   6 +-
 .../rest/cxf/service/SchemaServiceImpl.java     |   6 +-
 .../core/rest/cxf/service/TaskServiceImpl.java  |   4 +-
 .../main/resources/META-INF/web-fragment.xml    |  12 +
 .../src/main/resources/restCXFContext.xml       |  42 +-
 .../src/main/resources/wadl2html/index.xsl      |   6 +-
 .../activiti/ActivitiUserWorkflowAdapter.java   |  17 +-
 .../workflow/activiti/task/PasswordReset.java   |  24 +-
 .../core/workflow/activiti/task/Update.java     |  21 +-
 .../core/workflow/api/UserWorkflowAdapter.java  |   3 +-
 .../java/AbstractUserWorkflowAdapter.java       |   9 +-
 .../java/DefaultUserWorkflowAdapter.java        |  33 +-
 deb/core/pom.xml                                |   6 +
 .../client/console/panels/CamelRoutePanel.java  |   2 +-
 .../console/rest/CamelRouteRestClient.java      |   2 +-
 .../syncope/common/lib/to/CamelRouteTO.java     |   2 +
 .../processor/AnyObjectUpdateProcessor.java     |  20 -
 .../camel/processor/GroupUpdateProcessor.java   |  20 -
 .../processor/UserConfirmPwdResetProcessor.java |  14 +-
 .../UserStatusPropagationProcessor.java         |  15 +-
 .../processor/UserUpdateInSyncProcessor.java    |   6 +-
 .../camel/processor/UserUpdateProcessor.java    |  26 +-
 .../rest/api/service/CamelRouteService.java     |  25 +-
 .../rest/cxf/service/CamelRouteServiceImpl.java |   3 +-
 ext/pom.xml                                     |   1 +
 ext/swagger-ui/pom.xml                          | 107 +++++
 .../META-INF/resources/swagger/index.html       | 163 +++++++
 fit/console-reference/pom.xml                   |  80 +++-
 fit/core-reference/pom.xml                      | 146 ++++++-
 .../core/reference/AuthenticationITCase.java    |  24 +-
 .../fit/core/reference/CamelRouteITCase.java    |   2 +-
 .../fit/core/reference/ConfigurationITCase.java |  18 +-
 .../syncope/fit/core/reference/GroupITCase.java |  28 +-
 .../fit/core/reference/LoggerITCase.java        |  16 +
 .../fit/core/reference/MultitenancyITCase.java  |   2 +-
 .../fit/core/reference/PlainSchemaITCase.java   |   2 +-
 .../core/reference/PropagationTaskITCase.java   |   8 -
 .../fit/core/reference/ResourceITCase.java      |  11 +-
 .../fit/core/reference/SyncTaskITCase.java      |  61 ++-
 .../syncope/fit/core/reference/UserITCase.java  |  95 ++--
 .../fit/core/reference/UserSelfITCase.java      |  10 +-
 .../fit/core/reference/VirAttrITCase.java       | 333 +++++++-------
 .../fit/core/reference/VirSchemaITCase.java     |  50 ++-
 .../syncope/installer/enums/Containers.java     |   2 +-
 .../org/apache/syncope/installer/enums/DBs.java |   2 +-
 pom.xml                                         |  98 ++---
 src/main/asciidoc/docinfo-footer.html           |  23 +
 src/main/asciidoc/getting-started.adoc          |  59 +++
 .../getting-started/docinfo-footer.html         |  23 -
 .../getting-started/getting-started.adoc        |  69 ---
 .../getting-started/images/architecture.png     | Bin 62994 -> 0 bytes
 .../getting-started/images/architecture.xml     |  20 -
 .../images/identityLifecycle.png                | Bin 121230 -> 0 bytes
 .../asciidoc/getting-started/introduction.adoc  | 114 -----
 .../getting-started/systemRequirements.adoc     |  50 ---
 src/main/asciidoc/images/architecture.png       | Bin 0 -> 62994 bytes
 src/main/asciidoc/images/architecture.xml       |  20 +
 src/main/asciidoc/images/identityLifecycle.png  | Bin 0 -> 121230 bytes
 src/main/asciidoc/images/installer1.png         | Bin 0 -> 160690 bytes
 src/main/asciidoc/images/installer10.png        | Bin 0 -> 45440 bytes
 src/main/asciidoc/images/installer2.png         | Bin 0 -> 53017 bytes
 src/main/asciidoc/images/installer3.png         | Bin 0 -> 46889 bytes
 src/main/asciidoc/images/installer4.png         | Bin 0 -> 38073 bytes
 src/main/asciidoc/images/installer5.png         | Bin 0 -> 48416 bytes
 src/main/asciidoc/images/installer6.png         | Bin 0 -> 39613 bytes
 src/main/asciidoc/images/installer7.png         | Bin 0 -> 40130 bytes
 src/main/asciidoc/images/installer8.png         | Bin 0 -> 41467 bytes
 src/main/asciidoc/images/installer9.png         | Bin 0 -> 42059 bytes
 src/main/asciidoc/introduction.adoc             | 114 +++++
 src/main/asciidoc/obtain.adoc                   | 431 ++++++++++++++++++
 src/main/asciidoc/reference-guide.adoc          | 148 +++++++
 .../reference-guide/docinfo-footer.html         |  23 -
 .../reference-guide/reference-guide.adoc        | 148 -------
 src/main/asciidoc/systemRequirements.adoc       |  51 +++
 src/site/xdoc/architecture.xml                  |   2 +-
 381 files changed, 10198 insertions(+), 4432 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
index 667b525,93aa39a..fa40d42
--- a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
@@@ -184,15 -201,12 +184,15 @@@ public class SyncopeConsoleSession exte
      public <T> T getService(final MediaType mediaType, final Class<T> serviceClass) {
          T service;
  
 -        synchronized (clientFactory) {
 -            SyncopeClientFactoryBean.ContentType preType = clientFactory.getContentType();
 +        synchronized (SyncopeConsoleApplication.get().getClientFactory()) {
-             SyncopeClientFactoryBean.ContentType preType =
-                     SyncopeConsoleApplication.get().getClientFactory().getContentType();
++            SyncopeClientFactoryBean.ContentType preType = SyncopeConsoleApplication.get().getClientFactory().
++                    getContentType();
  
 -            clientFactory.setContentType(SyncopeClientFactoryBean.ContentType.fromString(mediaType.toString()));
 -            service = clientFactory.create(username, password).getService(serviceClass);
 -            clientFactory.setContentType(preType);
 +            SyncopeConsoleApplication.get().getClientFactory().
 +                    setContentType(SyncopeClientFactoryBean.ContentType.fromString(mediaType.toString()));
 +            service = SyncopeConsoleApplication.get().getClientFactory().
 +                    create(username, password).getService(serviceClass);
 +            SyncopeConsoleApplication.get().getClientFactory().setContentType(preType);
          }
  
          return service;

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/client/console/src/main/java/org/apache/syncope/client/console/pages/Login.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
index 847bd61,c66d650..b5850ad
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/ProvisioningModalPage.java
@@@ -190,8 -187,8 +190,8 @@@ public class ProvisioningModalPage<T ex
  
          private static final long serialVersionUID = 4287357360778016173L;
  
-         public StatusBeanProvider() {
+         StatusBeanProvider() {
 -            super("accountLink");
 +            super("connObjectLink");
          }
  
          @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
index 7dbe73e,238f13d..4f5e27a
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
@@@ -489,8 -486,8 +489,8 @@@ public class StatusModalPage<T extends 
  
          private static final long serialVersionUID = 4586969457669796621L;
  
-         public AttributableStatusProvider() {
+         AttributableStatusProvider() {
 -            super(statusOnly ? "resourceName" : "accountLink");
 +            super(statusOnly ? "resourceName" : "connObjectLink");
          }
  
          @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractResourceModal.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractResourceModal.java
index 15f4f02,1ed9050..21568eb
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractResourceModal.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractResourceModal.java
@@@ -38,46 -31,8 +38,46 @@@ public abstract class AbstractResourceM
  
      private static final long serialVersionUID = 1734415311027284221L;
  
 -    public AbstractResourceModal(final ModalWindow window, final PageReference pageRef) {
 -        super(window, pageRef);
 +    protected final List<ITab> tabs;
 +
 +    public AbstractResourceModal(final BaseModal<?> modal, final PageReference pageRef) {
 +        super(modal, pageRef);
 +
 +        this.tabs = new ArrayList<>();
 +        add(new AjaxBootstrapTabbedPanel<ITab>("tabbedPanel", tabs));
 +    }
 +
 +    private class AjaxBootstrapTabbedPanel<T extends ITab>
 +            extends de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel<T> {
 +
 +        private static final long serialVersionUID = 1L;
 +
-         public AjaxBootstrapTabbedPanel(final String id, final List<T> tabs) {
++        AjaxBootstrapTabbedPanel(final String id, final List<T> tabs) {
 +            super(id, tabs);
 +        }
 +
 +        @Override
 +        protected WebMarkupContainer newLink(final String linkId, final int index) {
 +            return new AjaxSubmitLink(linkId) {
 +
 +                private static final long serialVersionUID = 1L;
 +
 +                @Override
 +                protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
 +                    setSelectedTab(index);
 +                    if (target != null) {
 +                        target.add(AjaxBootstrapTabbedPanel.this);
 +                    }
 +                    onAjaxUpdate(target);
 +                }
 +
 +                @Override
 +                protected void onError(final AjaxRequestTarget target, final Form<?> form) {
 +                    modal.getFeedbackPanel().refresh(target);
 +                }
 +            };
 +        }
 +
      }
  
      public static class CreateEvent extends ModalEvent {

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
index 37cf8ac,89b856a..4d90788
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
@@@ -150,9 -155,9 +150,9 @@@ public class ResourceSecurityPanel exte
  
          private static final long serialVersionUID = 8060500161321947000L;
  
 -        private PolicyType type;
 +        private final PolicyType type;
  
-         public PolicyRenderer(final PolicyType type) {
+         PolicyRenderer(final PolicyType type) {
              super();
              this.type = type;
          }

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/client/console/src/main/java/org/apache/syncope/client/console/wizards/provision/ProvisionWizardBuilder.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/client/old_console/pom.xml
----------------------------------------------------------------------
diff --cc client/old_console/pom.xml
index ac9f17b,ac9f17b..a49170a
--- a/client/old_console/pom.xml
+++ b/client/old_console/pom.xml
@@@ -65,6 -65,6 +65,7 @@@ under the License
      <dependency>
        <groupId>org.apache.wicket</groupId>
        <artifactId>wicket-spring</artifactId>
++      <version>7.0.0</version>
        <!-- exclude spring framework that wicket pulls in -->
        <exclusions>
          <exclusion>

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutePanel.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/973cd50f/pom.xml
----------------------------------------------------------------------


[16/54] [abbrv] syncope git commit: Upgrading surefire, failsafe and checkstyle plugins

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/core/logic/src/main/java/org/apache/syncope/core/logic/init/LoggerLoader.java
----------------------------------------------------------------------
diff --cc core/logic/src/main/java/org/apache/syncope/core/logic/init/LoggerLoader.java
index c4c1928,0000000..13acaab
mode 100644,000000..100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/init/LoggerLoader.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/init/LoggerLoader.java
@@@ -1,113 -1,0 +1,113 @@@
 +/*
 + * 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.logic.init;
 +
 +import java.sql.Connection;
 +import java.sql.SQLException;
 +import java.util.Map;
 +import javax.sql.DataSource;
 +import org.apache.logging.log4j.Level;
 +import org.apache.logging.log4j.LogManager;
 +import org.apache.logging.log4j.core.Appender;
 +import org.apache.logging.log4j.core.LoggerContext;
 +import org.apache.logging.log4j.core.appender.db.jdbc.ColumnConfig;
 +import org.apache.logging.log4j.core.appender.db.jdbc.ConnectionSource;
 +import org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender;
 +import org.apache.logging.log4j.core.config.LoggerConfig;
 +import org.apache.syncope.core.misc.AuditManager;
 +import org.apache.syncope.core.misc.security.AuthContextUtils;
 +import org.apache.syncope.core.persistence.api.DomainsHolder;
 +import org.apache.syncope.core.persistence.api.SyncopeLoader;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.jdbc.datasource.DataSourceUtils;
 +import org.springframework.stereotype.Component;
 +
 +@Component
 +public class LoggerLoader implements SyncopeLoader {
 +
 +    @Autowired
 +    private DomainsHolder domainsHolder;
 +
 +    @Autowired
 +    private LoggerAccessor loggerAccessor;
 +
 +    @Override
 +    public Integer getPriority() {
 +        return 300;
 +    }
 +
 +    @Override
 +    public void load() {
 +        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
 +
 +        // Audit table and DataSource for each configured domain
 +        ColumnConfig[] columns = {
 +            ColumnConfig.createColumnConfig(ctx.getConfiguration(), "EVENT_DATE", null, null, "true", null, null),
 +            ColumnConfig.createColumnConfig(ctx.getConfiguration(), "LOGGER_LEVEL", "%level", null, null, null, null),
 +            ColumnConfig.createColumnConfig(ctx.getConfiguration(), "LOGGER", "%logger", null, null, null, null),
 +            ColumnConfig.createColumnConfig(ctx.getConfiguration(), "MESSAGE", "%message", null, null, null, null),
 +            ColumnConfig.createColumnConfig(ctx.getConfiguration(), "THROWABLE", "%ex{full}", null, null, null, null)
 +        };
 +        for (Map.Entry<String, DataSource> entry : domainsHolder.getDomains().entrySet()) {
 +            Appender appender = ctx.getConfiguration().getAppender("audit_for_" + entry.getKey());
 +            if (appender == null) {
 +                appender = JdbcAppender.createAppender(
 +                        "audit_for_" + entry.getKey(),
 +                        "false",
 +                        null,
 +                        new DataSourceConnectionSource(entry.getValue()),
 +                        "0",
 +                        "SYNCOPEAUDIT",
 +                        columns);
 +                appender.start();
 +                ctx.getConfiguration().addAppender(appender);
 +            }
 +
 +            LoggerConfig logConf = new LoggerConfig(AuditManager.getDomainAuditLoggerName(entry.getKey()), null, false);
 +            logConf.addAppender(appender, Level.DEBUG, null);
 +            ctx.getConfiguration().addLogger(AuditManager.getDomainAuditLoggerName(entry.getKey()), logConf);
 +
 +            AuthContextUtils.execWithAuthContext(entry.getKey(), new AuthContextUtils.Executable<Void>() {
 +
 +                @Override
 +                public Void exec() {
 +                    loggerAccessor.synchronizeLog4J(ctx);
 +                    return null;
 +                }
 +            });
 +        }
 +
 +        ctx.updateLoggers();
 +    }
 +
 +    private static class DataSourceConnectionSource implements ConnectionSource {
 +
 +        private final DataSource dataSource;
 +
-         public DataSourceConnectionSource(final DataSource dataSource) {
++        DataSourceConnectionSource(final DataSource dataSource) {
 +            this.dataSource = dataSource;
 +        }
 +
 +        @Override
 +        public Connection getConnection() throws SQLException {
 +            return DataSourceUtils.getConnection(dataSource);
 +        }
 +
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/core/misc/src/main/java/org/apache/syncope/core/misc/jexl/ClassFreeUberspectImpl.java
----------------------------------------------------------------------
diff --cc core/misc/src/main/java/org/apache/syncope/core/misc/jexl/ClassFreeUberspectImpl.java
index 662cb15,0000000..62e3dba
mode 100644,000000..100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/jexl/ClassFreeUberspectImpl.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/jexl/ClassFreeUberspectImpl.java
@@@ -1,43 -1,0 +1,43 @@@
 +/*
 + * 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.misc.jexl;
 +
 +import org.apache.commons.jexl2.JexlInfo;
 +import org.apache.commons.jexl2.introspection.JexlMethod;
 +import org.apache.commons.jexl2.introspection.JexlPropertyGet;
 +import org.apache.commons.jexl2.introspection.UberspectImpl;
 +import org.apache.commons.logging.Log;
 +
 +class ClassFreeUberspectImpl extends UberspectImpl {
 +
-     public ClassFreeUberspectImpl(final Log runtimeLogger) {
++    ClassFreeUberspectImpl(final Log runtimeLogger) {
 +        super(runtimeLogger);
 +    }
 +
 +    @Override
 +    public JexlPropertyGet getPropertyGet(final Object obj, final Object identifier, final JexlInfo info) {
 +        return "class".equals(identifier) ? null : super.getPropertyGet(obj, identifier, info);
 +    }
 +
 +    @Override
 +    public JexlMethod getMethod(final Object obj, final String method, final Object[] args, final JexlInfo info) {
 +        return "getClass".equals(method) ? null : super.getMethod(obj, method, args, info);
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
----------------------------------------------------------------------
diff --cc core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
index fd349a9,0000000..fa8847f
mode 100644,000000..100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
@@@ -1,55 -1,0 +1,55 @@@
 +/*
 + * 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.persistence.api;
 +
 +import java.util.Set;
 +import org.apache.syncope.common.lib.policy.AccountRuleConf;
 +import org.apache.syncope.common.lib.policy.PasswordRuleConf;
 +import org.apache.syncope.common.lib.report.ReportletConf;
 +import org.apache.syncope.core.persistence.api.dao.AccountRule;
 +import org.apache.syncope.core.persistence.api.dao.PasswordRule;
 +import org.apache.syncope.core.persistence.api.dao.Reportlet;
 +
 +public interface ImplementationLookup extends SyncopeLoader {
 +
-     public enum Type {
++    enum Type {
 +
 +        REPORTLET,
 +        ACCOUNT_RULE,
 +        PASSWORD_RULE,
 +        MAPPING_ITEM_TRANSFORMER,
 +        TASKJOBDELEGATE,
 +        LOGIC_ACTIONS,
 +        PROPAGATION_ACTIONS,
 +        SYNC_ACTIONS,
 +        PUSH_ACTIONS,
 +        SYNC_CORRELATION_RULE,
 +        PUSH_CORRELATION_RULE,
 +        VALIDATOR
 +
 +    }
 +
 +    Set<String> getClassNames(Type type);
 +
 +    Class<? extends Reportlet> getReportletClass(Class<? extends ReportletConf> reportletConfClass);
 +
 +    Class<? extends AccountRule> getAccountRuleClass(Class<? extends AccountRuleConf> accountRuleConfClass);
 +
 +    Class<? extends PasswordRule> getPasswordRuleClass(Class<? extends PasswordRuleConf> passwordRuleConfClass);
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
----------------------------------------------------------------------
diff --cc core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
index ddeb0e2,0000000..edd430e
mode 100644,000000..100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
@@@ -1,199 -1,0 +1,199 @@@
 +/*
 + * 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.persistence.jpa.content;
 +
 +import java.sql.ResultSet;
 +import java.sql.SQLException;
 +import java.sql.Types;
 +import java.text.ParseException;
 +import java.util.HashMap;
 +import java.util.Map;
 +import javax.sql.DataSource;
 +import org.apache.commons.codec.DecoderException;
 +import org.apache.commons.codec.binary.Hex;
 +import org.apache.syncope.core.misc.DataFormat;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.dao.DataAccessException;
 +import org.springframework.jdbc.core.JdbcTemplate;
 +import org.springframework.jdbc.core.ResultSetExtractor;
 +import org.xml.sax.Attributes;
 +import org.xml.sax.SAXException;
 +import org.xml.sax.helpers.DefaultHandler;
 +
 +/**
 + * SAX handler for generating SQL INSERT statements out of given XML file.
 + */
 +class ContentLoaderHandler extends DefaultHandler {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(ContentLoaderHandler.class);
 +
 +    private final DataSource dataSource;
 +
 +    private final String rootElement;
 +
-     public ContentLoaderHandler(final DataSource dataSource, final String rootElement) {
++    ContentLoaderHandler(final DataSource dataSource, final String rootElement) {
 +        this.dataSource = dataSource;
 +        this.rootElement = rootElement;
 +    }
 +
 +    private Object[] getParameters(final String tableName, final Attributes attrs) {
 +        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
 +
 +        Map<String, Integer> colTypes = jdbcTemplate.query("SELECT * FROM " + tableName + " WHERE 0=1",
 +                new ResultSetExtractor<Map<String, Integer>>() {
 +
 +                    @Override
 +                    public Map<String, Integer> extractData(final ResultSet rs) throws SQLException {
 +                        Map<String, Integer> colTypes = new HashMap<>();
 +                        for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
 +                            colTypes.put(
 +                                    rs.getMetaData().getColumnName(i).toUpperCase(),
 +                                    rs.getMetaData().getColumnType(i));
 +                        }
 +                        return colTypes;
 +                    }
 +                });
 +
 +        Object[] parameters = new Object[attrs.getLength()];
 +        for (int i = 0; i < attrs.getLength(); i++) {
 +            Integer colType = colTypes.get(attrs.getQName(i).toUpperCase());
 +            if (colType == null) {
 +                LOG.warn("No column type found for {}", attrs.getQName(i).toUpperCase());
 +                colType = Types.VARCHAR;
 +            }
 +
 +            switch (colType) {
 +                case Types.INTEGER:
 +                case Types.TINYINT:
 +                case Types.SMALLINT:
 +                    try {
 +                        parameters[i] = Integer.valueOf(attrs.getValue(i));
 +                    } catch (NumberFormatException e) {
 +                        LOG.error("Unparsable Integer '{}'", attrs.getValue(i));
 +                        parameters[i] = attrs.getValue(i);
 +                    }
 +                    break;
 +
 +                case Types.NUMERIC:
 +                case Types.DECIMAL:
 +                case Types.BIGINT:
 +                    try {
 +                        parameters[i] = Long.valueOf(attrs.getValue(i));
 +                    } catch (NumberFormatException e) {
 +                        LOG.error("Unparsable Long '{}'", attrs.getValue(i));
 +                        parameters[i] = attrs.getValue(i);
 +                    }
 +                    break;
 +
 +                case Types.DOUBLE:
 +                    try {
 +                        parameters[i] = Double.valueOf(attrs.getValue(i));
 +                    } catch (NumberFormatException e) {
 +                        LOG.error("Unparsable Double '{}'", attrs.getValue(i));
 +                        parameters[i] = attrs.getValue(i);
 +                    }
 +                    break;
 +
 +                case Types.REAL:
 +                case Types.FLOAT:
 +                    try {
 +                        parameters[i] = Float.valueOf(attrs.getValue(i));
 +                    } catch (NumberFormatException e) {
 +                        LOG.error("Unparsable Float '{}'", attrs.getValue(i));
 +                        parameters[i] = attrs.getValue(i);
 +                    }
 +                    break;
 +
 +                case Types.DATE:
 +                case Types.TIME:
 +                case Types.TIMESTAMP:
 +                    try {
 +                        parameters[i] = DataFormat.parseDate(attrs.getValue(i));
 +                    } catch (ParseException e) {
 +                        LOG.error("Unparsable Date '{}'", attrs.getValue(i));
 +                        parameters[i] = attrs.getValue(i);
 +                    }
 +                    break;
 +
 +                case Types.BIT:
 +                case Types.BOOLEAN:
 +                    parameters[i] = "1".equals(attrs.getValue(i)) ? Boolean.TRUE : Boolean.FALSE;
 +                    break;
 +
 +                case Types.BINARY:
 +                case Types.VARBINARY:
 +                case Types.LONGVARBINARY:
 +                    try {
 +                        parameters[i] = Hex.decodeHex(attrs.getValue(i).toCharArray());
 +                    } catch (DecoderException | IllegalArgumentException e) {
 +                        parameters[i] = attrs.getValue(i);
 +                    }
 +                    break;
 +
 +                case Types.BLOB:
 +                    try {
 +                        parameters[i] = Hex.decodeHex(attrs.getValue(i).toCharArray());
 +                    } catch (DecoderException | IllegalArgumentException e) {
 +                        LOG.warn("Error decoding hex string to specify a blob parameter", e);
 +                        parameters[i] = attrs.getValue(i);
 +                    } catch (Exception e) {
 +                        LOG.warn("Error creating a new blob parameter", e);
 +                    }
 +                    break;
 +
 +                default:
 +                    parameters[i] = attrs.getValue(i);
 +            }
 +        }
 +
 +        return parameters;
 +    }
 +
 +    @Override
 +    public void startElement(final String uri, final String localName, final String qName, final Attributes atts)
 +            throws SAXException {
 +
 +        // skip root element
 +        if (rootElement.equals(qName)) {
 +            return;
 +        }
 +
 +        StringBuilder query = new StringBuilder("INSERT INTO ").append(qName).append('(');
 +
 +        StringBuilder values = new StringBuilder();
 +
 +        for (int i = 0; i < atts.getLength(); i++) {
 +            query.append(atts.getQName(i));
 +            values.append('?');
 +            if (i < atts.getLength() - 1) {
 +                query.append(',');
 +                values.append(',');
 +            }
 +        }
 +        query.append(") VALUES (").append(values).append(')');
 +
 +        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
 +        try {
 +            jdbcTemplate.update(query.toString(), getParameters(qName, atts));
 +        } catch (DataAccessException e) {
 +            LOG.error("While trying to perform {}", query, e);
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNode.java
----------------------------------------------------------------------
diff --cc core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNode.java
index 98529e8,0000000..88a14e1
mode 100644,000000..100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNode.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNode.java
@@@ -1,106 -1,0 +1,106 @@@
 +/*
 + * 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.persistence.jpa.content;
 +
 +import java.util.HashSet;
 +import java.util.Set;
 +import org.apache.commons.lang3.builder.EqualsBuilder;
 +import org.apache.commons.lang3.builder.HashCodeBuilder;
 +
 +class MultiParentNode<T> {
 +
 +    private final T object;
 +
 +    private Set<MultiParentNode<T>> children;
 +
 +    private int level = 0;
 +
 +    private boolean exploited = false;
 +
-     public MultiParentNode(final T object) {
++    MultiParentNode(final T object) {
 +        this.object = object;
 +        children = new HashSet<>();
 +    }
 +
 +    public int getLevel() {
 +        return level;
 +    }
 +
 +    public void setLevel(final int level) {
 +        this.level = level;
 +    }
 +
 +    boolean isExploited() {
 +        return exploited;
 +    }
 +
 +    void setExploited(final boolean exploited) {
 +        this.exploited = exploited;
 +    }
 +
 +    public T getObject() {
 +        return object;
 +    }
 +
 +    public boolean isParent(final MultiParentNode<T> child) {
 +        return children.contains(child);
 +    }
 +
 +    public boolean isChild(final MultiParentNode<T> parent) {
 +        return parent.isParent(this);
 +    }
 +
 +    public Set<MultiParentNode<T>> getChildren() {
 +        return children;
 +    }
 +
 +    public void addParent(final MultiParentNode<T> parent) {
 +        if (parent != null) {
 +            parent.children.add(this);
 +        }
 +    }
 +
 +    public void removeParent(final MultiParentNode<T> parent) {
 +        if (parent != null) {
 +            parent.children.remove(this);
 +        }
 +    }
 +
 +    public void addChild(final MultiParentNode<T> child) {
 +        if (child != null) {
 +            children.add(child);
 +        }
 +    }
 +
 +    public void removeChild(final MultiParentNode<T> child) {
 +        if (child != null) {
 +            children.remove(child);
 +        }
 +    }
 +
 +    @Override
 +    public boolean equals(final Object obj) {
 +        return EqualsBuilder.reflectionEquals(this, obj);
 +    }
 +
 +    @Override
 +    public int hashCode() {
 +        return HashCodeBuilder.reflectionHashCode(this);
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
----------------------------------------------------------------------
diff --cc core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
index e87a22e,0000000..4c8297a
mode 100644,000000..100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
@@@ -1,155 -1,0 +1,155 @@@
 +/*
 + * 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.persistence.jpa.dao;
 +
 +import org.apache.commons.lang3.builder.EqualsBuilder;
 +import org.apache.commons.lang3.builder.HashCodeBuilder;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.AttrSchemaType;
 +
 +class SearchSupport {
 +
 +    static class SearchView {
 +
 +        protected String alias;
 +
 +        protected String name;
 +
 +        protected SearchView(final String alias, final String name) {
 +            this.alias = alias;
 +            this.name = name;
 +        }
 +
 +        @Override
 +        public boolean equals(final Object obj) {
 +            return EqualsBuilder.reflectionEquals(this, obj);
 +        }
 +
 +        @Override
 +        public int hashCode() {
 +            return HashCodeBuilder.reflectionHashCode(this);
 +        }
 +    }
 +
 +    private final AnyTypeKind anyTypeKind;
 +
-     public SearchSupport(final AnyTypeKind anyTypeKind) {
++    SearchSupport(final AnyTypeKind anyTypeKind) {
 +        this.anyTypeKind = anyTypeKind;
 +    }
 +
 +    public String fieldName(final AttrSchemaType attrSchemaType) {
 +        String result;
 +
 +        switch (attrSchemaType) {
 +            case Boolean:
 +                result = "booleanvalue";
 +                break;
 +
 +            case Date:
 +                result = "datevalue";
 +                break;
 +
 +            case Double:
 +                result = "doublevalue";
 +                break;
 +
 +            case Long:
 +                result = "longvalue";
 +                break;
 +
 +            case String:
 +            case Enum:
 +                result = "stringvalue";
 +                break;
 +
 +            default:
 +                result = null;
 +        }
 +
 +        return result;
 +    }
 +
 +    public SearchView field() {
 +        String result = "";
 +
 +        switch (anyTypeKind) {
 +            case ANY_OBJECT:
 +                result = "anyObject_search";
 +                break;
 +
 +            case GROUP:
 +                result = "group_search";
 +                break;
 +
 +            case USER:
 +            default:
 +                result = "user_search";
 +                break;
 +        }
 +
 +        return new SearchView("sv", result);
 +    }
 +
 +    public SearchView attr() {
 +        return new SearchView("sva", field().name + "_attr");
 +    }
 +
 +    public SearchView relationship() {
 +        String kind = anyTypeKind == AnyTypeKind.USER ? "u" : "a";
 +        return new SearchView("sv" + kind + "m", field().name + "_" + kind + "relationship");
 +    }
 +
 +    public SearchView membership() {
 +        String kind = anyTypeKind == AnyTypeKind.USER ? "u" : "a";
 +        return new SearchView("sv" + kind + "m", field().name + "_" + kind + "membership");
 +    }
 +
 +    public SearchView dyngroupmembership() {
 +        String kind = anyTypeKind == AnyTypeKind.USER ? "u" : "a";
 +        return new SearchView("sv" + kind + "dgm", field().name + "_" + kind + "dyngmemb");
 +    }
 +
 +    public SearchView role() {
 +        return new SearchView("svr", field().name + "_role");
 +    }
 +
 +    public SearchView dynrolemembership() {
 +        return new SearchView("svdr", field().name + "_dynrmemb");
 +    }
 +
 +    public SearchView nullAttr() {
 +        return new SearchView("svna", field().name + "_null_attr");
 +    }
 +
 +    public SearchView resource() {
 +        return new SearchView("svr", field().name + "_resource");
 +    }
 +
 +    public SearchView groupResource() {
 +        return new SearchView("svrr", field().name + "_group_res");
 +    }
 +
 +    public SearchView uniqueAttr() {
 +        return new SearchView("svua", field().name + "_unique_attr");
 +    }
 +
 +    public SearchView entitlements() {
 +        return new SearchView("sve", field().name + "_entitlements");
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutePanel.java
----------------------------------------------------------------------
diff --cc ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutePanel.java
index 005e23f,0000000..d68a8e9
mode 100644,000000..100644
--- a/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutePanel.java
+++ b/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutePanel.java
@@@ -1,178 -1,0 +1,178 @@@
 +/*
 + * 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.console.panels;
 +
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.Iterator;
 +import java.util.List;
 +import org.apache.syncope.client.console.annotations.ExtensionPanel;
 +import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 +import org.apache.syncope.client.console.rest.CamelRouteRestClient;
 +import org.apache.syncope.common.lib.to.CamelRouteTO;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.Entitlement;
 +import org.apache.wicket.PageReference;
 +import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
 +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 +import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
 +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
 +import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
 +import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
 +import org.apache.wicket.markup.html.WebMarkupContainer;
 +import org.apache.wicket.markup.repeater.Item;
 +import org.apache.wicket.model.AbstractReadOnlyModel;
 +import org.apache.wicket.model.IModel;
 +import org.apache.wicket.model.ResourceModel;
 +import org.apache.wicket.spring.injection.annot.SpringBean;
 +
 +@ExtensionPanel("Camel routes")
 +public class CamelRoutePanel extends AbstractExtensionPanel {
 +
 +    private static final long serialVersionUID = 1965360932245590233L;
 +
 +    private static final int CAMELROUTE_WIN_HEIGHT = 480;
 +
 +    private static final int CAMELROUTE_WIN_WIDTH = 800;
 +
 +    @SpringBean
 +    private CamelRouteRestClient restClient;
 +
 +    private ModalWindow editCamelRouteWin;
 +
 +    public CamelRoutePanel(final String id, final PageReference pageref) {
 +        super(id, pageref);
 +
 +        editCamelRouteWin = new ModalWindow("editCamelRouteWin");
 +        editCamelRouteWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
 +        editCamelRouteWin.setInitialHeight(CAMELROUTE_WIN_HEIGHT);
 +        editCamelRouteWin.setInitialWidth(CAMELROUTE_WIN_WIDTH);
 +        editCamelRouteWin.setCookieName("editCamelRouteWin-modal");
 +        add(editCamelRouteWin);
 +
 +        List<IColumn<CamelRouteTO, String>> routeCols = new ArrayList<>();
 +        routeCols.add(new PropertyColumn<CamelRouteTO, String>(new ResourceModel("key"), "key", "key"));
 +        routeCols.add(new AbstractColumn<CamelRouteTO, String>(new ResourceModel("actions", "")) {
 +
 +            private static final long serialVersionUID = 2054811145491901166L;
 +
 +            @Override
 +            public String getCssClass() {
 +                return "action";
 +            }
 +
 +            @Override
 +            public void populateItem(final Item<ICellPopulator<CamelRouteTO>> cellItem, final String componentId,
 +                    final IModel<CamelRouteTO> model) {
 +
 +                // Uncomment with something similar once SYNCOPE-156 is completed
 +                /* final ActionLinksPanel panel = new
 +                 * ActionLinksPanel(componentId, model, pageref);
 +                 *
 +                 * panel.add(new ActionLink() {
 +                 *
 +                 * private static final long serialVersionUID = -3722207913631435501L;
 +                 *
 +                 * @Override
 +                 * public void onClick(final AjaxRequestTarget target) {
 +                 *
 +                 * editCamelRouteWin.setPageCreator(new ModalWindow.PageCreator() {
 +                 *
 +                 * private static final long serialVersionUID = -7834632442532690940L;
 +                 *
 +                 * @Override
 +                 * public Page createPage() {
 +                 * return new CamelRouteModalPage(pageref, editCamelRouteWin,
 +                 * restClient.read(model.getObject().getKey()), false);
 +                 * }
 +                 *
 +                 * });
 +                 *
 +                 * editCamelRouteWin.show(target);
 +                 * }
 +                 * }, ActionLink.ActionType.EDIT, "CamelRoutes");
 +                 *
 +                 * cellItem.add(panel); */
 +            }
 +        });
 +
 +        final AjaxFallbackDefaultDataTable<CamelRouteTO, String> routeTable =
 +                new AjaxFallbackDefaultDataTable<>("camelRouteTable", routeCols, new CamelRouteProvider(), 50);
 +
 +        WebMarkupContainer routeContainer = new WebMarkupContainer("camelRoutesContainer");
 +        routeContainer.add(routeTable);
 +        routeContainer.setOutputMarkupId(true);
 +        MetaDataRoleAuthorizationStrategy.authorize(routeContainer, ENABLE, Entitlement.ROUTE_LIST);
 +        add(routeContainer);
 +    }
 +
 +    private class CamelRouteProvider extends SortableDataProvider<CamelRouteTO, String> {
 +
 +        private static final long serialVersionUID = -2917236020432105949L;
 +
 +        private final SortableDataProviderComparator<CamelRouteTO> comparator;
 +
-         public CamelRouteProvider() {
++       CamelRouteProvider() {
 +            setSort("key", SortOrder.ASCENDING);
 +            comparator = new SortableDataProviderComparator<>(this);
 +        }
 +
 +        @Override
 +        public Iterator<? extends CamelRouteTO> iterator(final long first, final long count) {
 +            List<CamelRouteTO> list = new ArrayList<>();
 +            if (restClient.isCamelEnabledFor(AnyTypeKind.USER)) {
 +                list.addAll(restClient.list(AnyTypeKind.USER));
 +            }
 +            if (restClient.isCamelEnabledFor(AnyTypeKind.GROUP)) {
 +                list.addAll(restClient.list(AnyTypeKind.GROUP));
 +            }
 +
 +            Collections.sort(list, comparator);
 +
 +            return list.subList((int) first, (int) first + (int) count).iterator();
 +        }
 +
 +        @Override
 +        public long size() {
 +            return (restClient.isCamelEnabledFor(AnyTypeKind.USER)
 +                    ? restClient.list(AnyTypeKind.USER).size()
 +                    : 0)
 +                    + (restClient.isCamelEnabledFor(AnyTypeKind.GROUP)
 +                            ? restClient.list(AnyTypeKind.GROUP).size()
 +                            : 0);
 +        }
 +
 +        @Override
 +        public IModel<CamelRouteTO> model(final CamelRouteTO route) {
 +            return new AbstractReadOnlyModel<CamelRouteTO>() {
 +
 +                private static final long serialVersionUID = 774694801558497248L;
 +
 +                @Override
 +                public CamelRouteTO getObject() {
 +                    return route;
 +                }
 +            };
 +        }
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/installer/src/main/java/org/apache/syncope/installer/enums/Containers.java
----------------------------------------------------------------------
diff --cc installer/src/main/java/org/apache/syncope/installer/enums/Containers.java
index ac8e036,ac8e036..f79de47
--- a/installer/src/main/java/org/apache/syncope/installer/enums/Containers.java
+++ b/installer/src/main/java/org/apache/syncope/installer/enums/Containers.java
@@@ -24,7 -24,7 +24,7 @@@ public enum Containers 
      JBOSS("jboss"),
      GLASSFISH("glassfish");
  
--    private Containers(final String name) {
++    Containers(final String name) {
          this.name = name;
      }
  

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/installer/src/main/java/org/apache/syncope/installer/enums/DBs.java
----------------------------------------------------------------------
diff --cc installer/src/main/java/org/apache/syncope/installer/enums/DBs.java
index 085b98f,9fcc92e..3e15b8c
--- a/installer/src/main/java/org/apache/syncope/installer/enums/DBs.java
+++ b/installer/src/main/java/org/apache/syncope/installer/enums/DBs.java
@@@ -26,7 -26,7 +26,7 @@@ public enum DBs 
      SQLSERVER("sqlserver"),
      ORACLE("oracle");
  
--    private DBs(final String name) {
++    DBs(final String name) {
          this.name = name;
      }
  

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/pom.xml
----------------------------------------------------------------------
diff --cc pom.xml
index 50e3522,4ef0802..78179bf
--- a/pom.xml
+++ b/pom.xml
@@@ -1140,7 -1067,65 +1140,7 @@@ under the License
            <artifactId>openjpa-maven-plugin</artifactId>
            <version>${openjpa.version}</version>
          </plugin>
-         
 -        <plugin>
 -          <groupId>org.codehaus.mojo</groupId>
 -          <artifactId>xml-maven-plugin</artifactId>
 -          <version>1.0</version>
 -          <dependencies>
 -            <dependency>
 -              <groupId>xalan</groupId>
 -              <artifactId>xalan</artifactId>
 -              <version>2.7.1</version>
 -            </dependency>
 -          </dependencies>
 -        </plugin>
 -        <plugin>
 -          <groupId>org.apache.maven.plugins</groupId>
 -          <artifactId>maven-surefire-plugin</artifactId>
 -          <version>2.19</version>
 -          <configuration>
 -            <redirectTestOutputToFile>true</redirectTestOutputToFile>
 -            <encoding>utf-8</encoding>
 -            <runOrder>alphabetical</runOrder>
 -            <argLine>-Xms512m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=512m</argLine>
 -          </configuration>
 -        </plugin>
 -        <plugin>
 -          <groupId>org.apache.maven.plugins</groupId>
 -          <artifactId>maven-war-plugin</artifactId>
 -          <version>2.6</version>
 -          <configuration>
 -            <attachClasses>true</attachClasses>
 -          </configuration>
 -        </plugin>
 -        <plugin>
 -          <groupId>org.codehaus.mojo</groupId>
 -          <artifactId>selenium-maven-plugin</artifactId>
 -          <version>2.3</version>
 -        </plugin>
 -        <plugin>
 -          <groupId>org.apache.maven.plugins</groupId>
 -          <artifactId>maven-failsafe-plugin</artifactId>
 -          <version>2.19</version>
 -          <configuration>
 -            <redirectTestOutputToFile>true</redirectTestOutputToFile>
 -            <encoding>utf-8</encoding>
 -            <runOrder>alphabetical</runOrder>
 -          </configuration>
 -          <executions>
 -            <execution>
 -              <goals>
 -                <goal>integration-test</goal>
 -                <goal>verify</goal>
 -              </goals>
 -            </execution>
 -          </executions>
 -        </plugin>
 -        <plugin>
 -          <groupId>org.apache.maven.plugins</groupId>
 -          <artifactId>maven-antrun-plugin</artifactId>
 -          <version>1.8</version>
 -        </plugin>
++
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
@@@ -1231,43 -1179,42 +1231,43 @@@
              </container>
            </configuration>
          </plugin>
 +        
          <plugin>
 -          <groupId>org.codehaus.mojo</groupId>
 -          <artifactId>build-helper-maven-plugin</artifactId>
 -          <version>1.9</version>
 -        </plugin>
 -        <plugin>
 -          <groupId>org.zeroturnaround</groupId>
 -          <artifactId>jrebel-maven-plugin</artifactId>
 -          <version>1.1.5</version>
 +          <groupId>org.apache.maven.plugins</groupId>
 +          <artifactId>maven-surefire-plugin</artifactId>
-           <version>2.18.1</version>
++          <version>2.19</version>
 +          <configuration>
 +            <redirectTestOutputToFile>true</redirectTestOutputToFile>
 +            <encoding>utf-8</encoding>
 +            <runOrder>alphabetical</runOrder>
 +            <argLine>-Xms512m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=512m -Xss256k</argLine>
 +          </configuration>
          </plugin>
          <plugin>
 -          <groupId>org.apache.felix</groupId>
 -          <artifactId>maven-bundle-plugin</artifactId>
 -          <version>2.5.0</version>
 +          <groupId>org.apache.maven.plugins</groupId>
 +          <artifactId>maven-failsafe-plugin</artifactId>
-           <version>2.18.1</version>
++          <version>2.19</version>
            <configuration>
 -            <supportedProjectTypes>
 -              <supportedProjectType>jar</supportedProjectType>
 -              <supportedProjectType>war</supportedProjectType>
 -              <supportedProjectType>bundle</supportedProjectType>
 -            </supportedProjectTypes>
 +            <redirectTestOutputToFile>true</redirectTestOutputToFile>
 +            <encoding>utf-8</encoding>
 +            <runOrder>alphabetical</runOrder>
            </configuration>
 +          <executions>
 +            <execution>
 +              <goals>
 +                <goal>integration-test</goal>
 +                <goal>verify</goal>
 +              </goals>
 +            </execution>
 +          </executions>
          </plugin>
 +        
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-checkstyle-plugin</artifactId>
-           <version>2.16</version>
+           <version>2.17</version>
 -          <dependencies>
 -            <dependency>
 -              <groupId>org.apache.syncope</groupId>
 -              <artifactId>syncope-build-tools</artifactId>
 -              <version>${project.version}</version>
 -              <classifier>classes</classifier>
 -            </dependency>
 -          </dependencies>
            <configuration>
 -            <configLocation>org/apache/syncope/checkstyle.xml</configLocation>
 +            <configLocation>${rootpom.basedir}/src/main/resources/org/apache/syncope/checkstyle.xml</configLocation>
              <targetJdk>${targetJdk}</targetJdk>
            </configuration>
          </plugin>


[14/54] [abbrv] syncope git commit: Upgrading Spring

Posted by fm...@apache.org.
Upgrading Spring


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

Branch: refs/heads/SYNCOPE-156
Commit: 1c459bff536729e278bc0d5d8bb53f1934bb6f49
Parents: 6f4082c
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Mon Oct 19 10:18:47 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Mon Oct 19 10:18:47 2015 +0200

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/1c459bff/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c7095e2..50e3522 100644
--- a/pom.xml
+++ b/pom.xml
@@ -332,7 +332,7 @@ under the License.
 
     <jackson.version>2.6.3</jackson.version>
 
-    <spring.version>4.2.1.RELEASE</spring.version>
+    <spring.version>4.2.2.RELEASE</spring.version>
     <spring-security.version>4.0.2.RELEASE</spring-security.version>
 
     <openjpa.version>2.4.0</openjpa.version>


[43/54] [abbrv] syncope git commit: [SYNCOPE-709] Refactoring completed

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttrValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttrValue.java
index 73645b4..2eca97c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttrValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttrValue.java
@@ -57,7 +57,7 @@ public class JPAUPlainAttrValue extends AbstractPlainAttrValue implements UPlain
     }
 
     @Override
-    public void setAttr(final PlainAttr attr) {
+    public void setAttr(final PlainAttr<?> attr) {
         checkType(attr, JPAUPlainAttr.class);
         this.attribute = (JPAUPlainAttr) attr;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUVirAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUVirAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUVirAttr.java
deleted file mode 100644
index a6931ce..0000000
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUVirAttr.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.persistence.jpa.entity.user;
-
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.ManyToOne;
-import javax.persistence.Table;
-import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
-import org.apache.syncope.core.persistence.api.entity.user.User;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractVirAttr;
-
-@Entity
-@Table(name = JPAUVirAttr.TABLE)
-public class JPAUVirAttr extends AbstractVirAttr<User> implements UVirAttr {
-
-    private static final long serialVersionUID = 2943450934283989741L;
-
-    public static final String TABLE = "UVirAttr";
-
-    @Id
-    private Long id;
-
-    @ManyToOne
-    private JPAUser owner;
-
-    @Override
-    public Long getKey() {
-        return id;
-    }
-
-    @Override
-    public User getOwner() {
-        return owner;
-    }
-
-    @Override
-    public void setOwner(final User owner) {
-        checkType(owner, JPAUser.class);
-        this.owner = (JPAUser) owner;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
index 74335ec..9ba4fea 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
@@ -54,7 +54,6 @@ import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
 import org.apache.syncope.core.persistence.api.entity.user.UDerAttr;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
-import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResource;
 import org.apache.syncope.core.persistence.jpa.entity.JPASecurityQuestion;
@@ -75,7 +74,7 @@ import org.apache.syncope.core.persistence.jpa.entity.JPARole;
 @Entity
 @Table(name = JPAUser.TABLE)
 @Cacheable
-public class JPAUser extends AbstractAny<UPlainAttr, UDerAttr, UVirAttr> implements User {
+public class JPAUser extends AbstractAny<UPlainAttr, UDerAttr> implements User {
 
     private static final long serialVersionUID = -3905046855521446823L;
 
@@ -105,10 +104,6 @@ public class JPAUser extends AbstractAny<UPlainAttr, UDerAttr, UVirAttr> impleme
     @Valid
     private List<JPAUDerAttr> derAttrs = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
-    @Valid
-    private List<JPAUVirAttr> virAttrs = new ArrayList<>();
-
     private String workflowId;
 
     @Column(nullable = true)
@@ -322,23 +317,6 @@ public class JPAUser extends AbstractAny<UPlainAttr, UDerAttr, UVirAttr> impleme
     }
 
     @Override
-    public boolean add(final UVirAttr attr) {
-        checkType(attr, JPAUVirAttr.class);
-        return virAttrs.add((JPAUVirAttr) attr);
-    }
-
-    @Override
-    public boolean remove(final UVirAttr attr) {
-        checkType(attr, JPAUVirAttr.class);
-        return virAttrs.remove((JPAUVirAttr) attr);
-    }
-
-    @Override
-    public List<? extends UVirAttr> getVirAttrs() {
-        return virAttrs;
-    }
-
-    @Override
     public String getWorkflowId() {
         return workflowId;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
index fb5a0a9..e7f3a85 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
@@ -25,7 +25,12 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
@@ -39,7 +44,7 @@ public class ExternalResourceValidator extends AbstractValidator<ExternalResourc
     private boolean isValid(final MappingItem item, final ConstraintValidatorContext context) {
         if (StringUtils.isBlank(item.getExtAttrName())) {
             context.buildConstraintViolationWithTemplate(
-                    getTemplate(EntityViolationType.InvalidMapping, item + ".extAttrName is null")).
+                    getTemplate(EntityViolationType.InvalidMapping, item + " - extAttrName is null")).
                     addPropertyNode("extAttrName").addConstraintViolation();
 
             return false;
@@ -47,7 +52,7 @@ public class ExternalResourceValidator extends AbstractValidator<ExternalResourc
 
         if (StringUtils.isBlank(item.getIntAttrName())) {
             context.buildConstraintViolationWithTemplate(
-                    getTemplate(EntityViolationType.InvalidMapping, item + ".intAttrName is null")).
+                    getTemplate(EntityViolationType.InvalidMapping, item + " - intAttrName is null")).
                     addPropertyNode("intAttrName").addConstraintViolation();
 
             return false;
@@ -55,12 +60,46 @@ public class ExternalResourceValidator extends AbstractValidator<ExternalResourc
 
         if (item.getPurpose() == null) {
             context.buildConstraintViolationWithTemplate(
-                    getTemplate(EntityViolationType.InvalidMapping, item + ".purpose is null")).
+                    getTemplate(EntityViolationType.InvalidMapping, item + " - purpose is null")).
                     addPropertyNode("purpose").addConstraintViolation();
 
             return false;
         }
 
+        if (item.getIntMappingType() == IntMappingType.AnyObjectVirtualSchema
+                || item.getIntMappingType() == IntMappingType.GroupVirtualSchema
+                || item.getIntMappingType() == IntMappingType.UserVirtualSchema) {
+
+            if (item.getPurpose() != MappingPurpose.PROPAGATION) {
+                context.buildConstraintViolationWithTemplate(
+                        getTemplate(EntityViolationType.InvalidMapping,
+                                " - only " + MappingPurpose.PROPAGATION.name() + " allowed for virtual")).
+                        addPropertyNode("purpose").addConstraintViolation();
+
+                return false;
+            }
+
+            if (item.getMapping() == null) {
+                context.buildConstraintViolationWithTemplate(
+                        getTemplate(EntityViolationType.InvalidMapping,
+                                " - need to explicitly set mapping for further checks")).
+                        addPropertyNode("mapping").addConstraintViolation();
+
+                return false;
+            }
+
+            VirSchema schema = ApplicationContextProvider.getBeanFactory().getBean(VirSchemaDAO.class).
+                    find(item.getIntAttrName());
+            if (schema != null && schema.getProvision().equals(item.getMapping().getProvision())) {
+                context.buildConstraintViolationWithTemplate(
+                        getTemplate(EntityViolationType.InvalidMapping,
+                                " - no need to map virtual schema on linking resource")).
+                        addPropertyNode("intAttrName").addConstraintViolation();
+
+                return false;
+            }
+        }
+
         return true;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java
index d5d546b..2613a22 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java
@@ -33,7 +33,7 @@ import javax.validation.Payload;
 @Documented
 public @interface PlainAttrCheck {
 
-    String message() default "{org.apache.syncope.syncope.validation.attr}";
+    String message() default "{org.apache.syncope.core.persistence.validation.attr}";
 
     Class<?>[] groups() default {};
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java
index 5dc7f55..f2c3c86 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java
@@ -43,7 +43,7 @@ public class PlainAttrValidator extends AbstractValidator<PlainAttrCheck, PlainA
 
             if (!isValid) {
                 LOG.error("Invalid values for attribute " + object + ": " + "schema=" + object.getSchema().getKey()
-                        + ", " + "values={}", object.getValuesAsStrings());
+                        + ", values={}", object.getValuesAsStrings());
 
                 context.disableDefaultConstraintViolation();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
index 02c8c8b..5ddee8c 100644
--- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
+++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-oracle.xml
@@ -337,31 +337,6 @@ under the License.
     </attributes>
   </entity>
 
-  <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAVirAttr">
-    <attributes>
-      <id name="id">
-        <generated-value generator="SEQ_AVirAttr" strategy="TABLE"/>
-        <table-generator name="SEQ_AVirAttr" pk-column-value="SEQ_AVirAttr" initial-value="1000"/>
-      </id>
-    </attributes>
-  </entity>
-  <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr">
-    <attributes>
-      <id name="id">
-        <generated-value generator="SEQ_UVirAttr" strategy="TABLE"/>
-        <table-generator name="SEQ_UVirAttr" pk-column-value="SEQ_UVirAttr" initial-value="1000"/>
-      </id>
-    </attributes>
-  </entity>
-  <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPAGVirAttr">
-    <attributes>
-      <id name="id">
-        <generated-value generator="SEQ_GVirAttr" strategy="TABLE"/>
-        <table-generator name="SEQ_GVirAttr" pk-column-value="SEQ_GVirAttr" initial-value="1000"/>
-      </id>
-    </attributes>
-  </entity>
-
   <entity class="org.apache.syncope.core.persistence.jpa.entity.JPAAnyTemplateRealm">
     <attributes>
       <id name="id">

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
index 02c8c8b..5ddee8c 100644
--- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
+++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm-sqlserver.xml
@@ -337,31 +337,6 @@ under the License.
     </attributes>
   </entity>
 
-  <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAVirAttr">
-    <attributes>
-      <id name="id">
-        <generated-value generator="SEQ_AVirAttr" strategy="TABLE"/>
-        <table-generator name="SEQ_AVirAttr" pk-column-value="SEQ_AVirAttr" initial-value="1000"/>
-      </id>
-    </attributes>
-  </entity>
-  <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr">
-    <attributes>
-      <id name="id">
-        <generated-value generator="SEQ_UVirAttr" strategy="TABLE"/>
-        <table-generator name="SEQ_UVirAttr" pk-column-value="SEQ_UVirAttr" initial-value="1000"/>
-      </id>
-    </attributes>
-  </entity>
-  <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPAGVirAttr">
-    <attributes>
-      <id name="id">
-        <generated-value generator="SEQ_GVirAttr" strategy="TABLE"/>
-        <table-generator name="SEQ_GVirAttr" pk-column-value="SEQ_GVirAttr" initial-value="1000"/>
-      </id>
-    </attributes>
-  </entity>
-
   <entity class="org.apache.syncope.core.persistence.jpa.entity.JPAAnyTemplateRealm">
     <attributes>
       <id name="id">

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml b/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
index b5c54b6..f4f2b07 100644
--- a/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
+++ b/core/persistence-jpa/src/main/resources/META-INF/spring-orm.xml
@@ -384,31 +384,6 @@ under the License.
       </id>
     </attributes>
   </entity>
-
-  <entity class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAVirAttr">
-    <attributes>
-      <id name="id">
-        <generated-value generator="SEQ_AVirAttr" strategy="TABLE"/>
-        <table-generator name="SEQ_AVirAttr" pk-column-value="SEQ_AVirAttr" initial-value="1000"/>
-      </id>
-    </attributes>
-  </entity>
-  <entity class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr">
-    <attributes>
-      <id name="id">
-        <generated-value generator="SEQ_UVirAttr" strategy="TABLE"/>
-        <table-generator name="SEQ_UVirAttr" pk-column-value="SEQ_UVirAttr" initial-value="1000"/>
-      </id>
-    </attributes>
-  </entity>
-  <entity class="org.apache.syncope.core.persistence.jpa.entity.group.JPAGVirAttr">
-    <attributes>
-      <id name="id">
-        <generated-value generator="SEQ_GVirAttr" strategy="TABLE"/>
-        <table-generator name="SEQ_GVirAttr" pk-column-value="SEQ_GVirAttr" initial-value="1000"/>
-      </id>
-    </attributes>
-  </entity>
   
   <entity class="org.apache.syncope.core.persistence.jpa.entity.JPAAnyTemplateRealm">
     <attributes>

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/resources/indexes.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/indexes.xml b/core/persistence-jpa/src/main/resources/indexes.xml
index f5ae8f7..a2d4c62 100644
--- a/core/persistence-jpa/src/main/resources/indexes.xml
+++ b/core/persistence-jpa/src/main/resources/indexes.xml
@@ -68,9 +68,5 @@ under the License.
   <entry key="GDerAttr_owner_id_index">CREATE INDEX GDerAttr_owner_id_index on GDerAttr(owner_id)</entry>
   <entry key="ADerAttr_owner_id_index">CREATE INDEX ADerAttr_owner_id_index on ADerAttr(owner_id)</entry>
 
-  <entry key="UVirAttr_owner_id_index">CREATE INDEX UVirAttr_owner_id_index on UVirAttr(owner_id)</entry>
-  <entry key="GVirAttr_owner_id_index">CREATE INDEX GVirAttr_owner_id_index on GVirAttr(owner_id)</entry>
-  <entry key="AVirAttr_owner_id_index">CREATE INDEX AVirAttr_owner_id_index on AVirAttr(owner_id)</entry>
-
   <entry key="Task_executedIndex">CREATE INDEX Task_executedIndex ON Task(executed)</entry>
 </properties>

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
index fe53386..3cea9ab 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
@@ -118,7 +118,6 @@ public class PlainAttrTest extends AbstractTest {
         user.add(attribute);
 
         Exception thrown = null;
-
         try {
             attribute.add("A", anyUtilsFactory.getInstance(AnyTypeKind.USER));
         } catch (ValidationException e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
index bdfd645..0fc2a3e 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
@@ -260,6 +260,52 @@ public class ResourceTest extends AbstractTest {
     }
 
     @Test
+    public void saveVirtualMapping() {
+        ExternalResource resource = entityFactory.newEntity(ExternalResource.class);
+        resource.setKey("ws-target-resource-virtual-mapping");
+        resource.setPropagationPriority(2);
+        resource.setPropagationPrimary(true);
+
+        Provision provision = entityFactory.newEntity(Provision.class);
+        provision.setAnyType(anyTypeDAO.findUser());
+        provision.setObjectClass(ObjectClass.ACCOUNT);
+        provision.setResource(resource);
+        resource.add(provision);
+
+        Mapping mapping = entityFactory.newEntity(Mapping.class);
+        mapping.setProvision(provision);
+        provision.setMapping(mapping);
+
+        MappingItem connObjectKey = entityFactory.newEntity(MappingItem.class);
+        connObjectKey.setExtAttrName("username");
+        connObjectKey.setIntAttrName("fullname");
+        connObjectKey.setIntMappingType(IntMappingType.UserKey);
+        connObjectKey.setPurpose(MappingPurpose.BOTH);
+        mapping.setConnObjectKeyItem(connObjectKey);
+
+        MappingItem virtualMapItem = entityFactory.newEntity(MappingItem.class);
+        virtualMapItem.setIntMappingType(IntMappingType.UserVirtualSchema);
+        virtualMapItem.setIntAttrName("virtualReadOnly");
+        virtualMapItem.setExtAttrName("TEST");
+        virtualMapItem.setPurpose(MappingPurpose.BOTH);
+        virtualMapItem.setMapping(mapping);
+        mapping.add(virtualMapItem);
+
+        ConnInstance connector = resourceDAO.find("ws-target-resource-1").getConnector();
+        resource.setConnector(connector);
+
+        try {
+            resourceDAO.save(resource);
+            fail();
+        } catch (InvalidEntityException e) {
+            assertNotNull(e);
+        }
+
+        virtualMapItem.setPurpose(MappingPurpose.PROPAGATION);
+        resourceDAO.save(resource);
+    }
+
+    @Test
     public void saveWithGroupMappingType() {
         ExternalResource resource = entityFactory.newEntity(ExternalResource.class);
         resource.setKey("ws-target-resource-basic-save-invalid");

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/TaskTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/TaskTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/TaskTest.java
index 7377475..f39f06f 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/TaskTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/TaskTest.java
@@ -113,6 +113,7 @@ public class TaskTest extends AbstractTest {
         PropagationTask task = entityFactory.newEntity(PropagationTask.class);
         task.setResource(resource);
         task.setAnyTypeKind(AnyTypeKind.USER);
+        task.setAnyType(AnyTypeKind.USER.name());
         task.setOperation(ResourceOperation.CREATE);
         task.setConnObjectKey("one@two.com");
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirAttrTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirAttrTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirAttrTest.java
deleted file mode 100644
index fd13cd6..0000000
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirAttrTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.persistence.jpa.inner;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import java.util.List;
-import org.apache.syncope.core.persistence.api.dao.GroupDAO;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
-import org.apache.syncope.core.persistence.api.dao.VirAttrDAO;
-import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
-import org.apache.syncope.core.persistence.api.entity.VirSchema;
-import org.apache.syncope.core.persistence.api.entity.group.GVirAttr;
-import org.apache.syncope.core.persistence.api.entity.group.Group;
-import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
-import org.apache.syncope.core.persistence.api.entity.user.User;
-import org.apache.syncope.core.persistence.jpa.AbstractTest;
-import org.junit.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-
-@Transactional("Master")
-public class VirAttrTest extends AbstractTest {
-
-    @Autowired
-    private VirAttrDAO virAttrDAO;
-
-    @Autowired
-    private UserDAO userDAO;
-
-    @Autowired
-    private GroupDAO groupDAO;
-
-    @Autowired
-    private VirSchemaDAO virSchemaDAO;
-
-    @Test
-    public void findAll() {
-        List<UVirAttr> list = virAttrDAO.findAll(UVirAttr.class);
-        assertEquals("did not get expected number of derived attributes ", 1, list.size());
-    }
-
-    @Test
-    public void findById() {
-        UVirAttr attribute = virAttrDAO.find(100L, UVirAttr.class);
-        assertNotNull("did not find expected attribute schema", attribute);
-    }
-
-    @Test
-    public void saveUVirAttribute() {
-        VirSchema virSchema = virSchemaDAO.find("virtualdata");
-        assertNotNull(virSchema);
-
-        User owner = userDAO.find(3L);
-        assertNotNull("did not get expected user", owner);
-
-        UVirAttr virAttr = entityFactory.newEntity(UVirAttr.class);
-        virAttr.setOwner(owner);
-        virAttr.setSchema(virSchema);
-
-        virAttr = virAttrDAO.save(virAttr);
-
-        UVirAttr actual = virAttrDAO.find(virAttr.getKey(), UVirAttr.class);
-        assertNotNull("expected save to work", actual);
-        assertEquals(virAttr, actual);
-    }
-
-    @Test
-    public void saveGVirAttribute() {
-        VirSchema virSchema = virSchemaDAO.find("rvirtualdata");
-        assertNotNull(virSchema);
-
-        Group owner = groupDAO.find(3L);
-        assertNotNull("did not get expected membership", owner);
-
-        GVirAttr virAttr = entityFactory.newEntity(GVirAttr.class);
-        virAttr.setOwner(owner);
-        virAttr.setSchema(virSchema);
-
-        virAttr = virAttrDAO.save(virAttr);
-
-        GVirAttr actual = virAttrDAO.find(virAttr.getKey(), GVirAttr.class);
-        assertNotNull("expected save to work", actual);
-        assertEquals(virAttr, actual);
-    }
-
-    @Test
-    public void delete() {
-        UVirAttr attribute = virAttrDAO.find(100L, UVirAttr.class);
-        String attributeSchemaName = attribute.getSchema().getKey();
-
-        virAttrDAO.delete(attribute.getKey(), UVirAttr.class);
-
-        UVirAttr actual = virAttrDAO.find(1000L, UVirAttr.class);
-        assertNull("delete did not work", actual);
-
-        VirSchema attributeSchema = virSchemaDAO.find(attributeSchemaName);
-        assertNotNull("user virtual attribute schema deleted " + "when deleting values", attributeSchema);
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirSchemaTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirSchemaTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirSchemaTest.java
index 10970d1..66bd6cb 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirSchemaTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/VirSchemaTest.java
@@ -43,7 +43,7 @@ public class VirSchemaTest extends AbstractTest {
     @Test
     public void findAll() {
         List<VirSchema> list = virSchemaDAO.findAll();
-        assertEquals(4, list.size());
+        assertEquals(3, list.size());
     }
 
     @Test
@@ -54,15 +54,17 @@ public class VirSchemaTest extends AbstractTest {
 
     @Test
     public void save() {
-        VirSchema virtualAttributeSchema = entityFactory.newEntity(VirSchema.class);
-        virtualAttributeSchema.setKey("virtual");
-        virtualAttributeSchema.setReadonly(true);
+        VirSchema virSchema = entityFactory.newEntity(VirSchema.class);
+        virSchema.setKey("virtual");
+        virSchema.setReadonly(true);
+        virSchema.setExtAttrName("EXT_ATTR");
 
-        virSchemaDAO.save(virtualAttributeSchema);
+        virSchemaDAO.save(virSchema);
 
         VirSchema actual = virSchemaDAO.find("virtual");
         assertNotNull("expected save to work", actual);
         assertTrue(actual.isReadonly());
+        assertEquals("EXT_ATTR", actual.getExtAttrName());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ResourceTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ResourceTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ResourceTest.java
index 5628c29..2a8a090 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ResourceTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ResourceTest.java
@@ -38,8 +38,10 @@ import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
 import org.apache.syncope.core.persistence.api.dao.TaskDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
 import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
@@ -75,6 +77,9 @@ public class ResourceTest extends AbstractTest {
     @Autowired
     private PolicyDAO policyDAO;
 
+    @Autowired
+    private VirSchemaDAO virSchemaDAO;
+
     @Test
     public void createWithPasswordPolicy() {
         final String resourceName = "resourceWithPasswordPolicy";
@@ -269,7 +274,11 @@ public class ResourceTest extends AbstractTest {
             itemKeys.add(item.getKey());
         }
 
-        ldap.remove(ldap.getProvision(anyTypeDAO.findGroup()));
+        Provision groupProvision = ldap.getProvision(anyTypeDAO.findGroup());
+        ldap.remove(groupProvision);
+        for (VirSchema schema : virSchemaDAO.findByProvision(groupProvision)) {
+            virSchemaDAO.delete(schema.getKey());
+        }
 
         // need to avoid any class not defined in this Maven module
         ldap.getPropagationActionsClassNames().clear();
@@ -277,8 +286,8 @@ public class ResourceTest extends AbstractTest {
         resourceDAO.save(ldap);
         resourceDAO.flush();
 
-        for (Long itemId : itemKeys) {
-            assertNull(entityManager().find(JPAMappingItem.class, itemId));
+        for (Long itemKey : itemKeys) {
+            assertNull(entityManager().find(JPAMappingItem.class, itemKey));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java
index 2b3d6c7..53f88d8 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java
@@ -92,6 +92,7 @@ public class TaskTest extends AbstractTest {
         PropagationTask task = entityFactory.newEntity(PropagationTask.class);
         task.setResource(resource);
         task.setAnyTypeKind(AnyTypeKind.USER);
+        task.setAnyType(AnyTypeKind.USER.name());
         task.setOperation(ResourceOperation.CREATE);
         task.setConnObjectKey("one@two.com");
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/VirSchemaTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/VirSchemaTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/VirSchemaTest.java
new file mode 100644
index 0000000..bd68313
--- /dev/null
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/VirSchemaTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.persistence.jpa.outer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional("Master")
+public class VirSchemaTest extends AbstractTest {
+
+    @Autowired
+    private VirSchemaDAO virSchemaDAO;
+
+    @Autowired
+    private ExternalResourceDAO resourceDAO;
+
+    @Test
+    public void deal() {
+        Provision provision = resourceDAO.findProvision(15L);
+        assertNotNull(provision);
+        assertTrue(virSchemaDAO.findByProvision(provision).isEmpty());
+
+        VirSchema virSchema = entityFactory.newEntity(VirSchema.class);
+        virSchema.setKey("vSchema");
+        virSchema.setReadonly(true);
+        virSchema.setExtAttrName("EXT_ATTR");
+        virSchema.setProvision(provision);
+
+        virSchemaDAO.save(virSchema);
+        virSchemaDAO.flush();
+
+        virSchema = virSchemaDAO.find("vSchema");
+        assertNotNull("expected save to work", virSchema);
+        assertTrue(virSchema.isReadonly());
+        assertEquals("EXT_ATTR", virSchema.getExtAttrName());
+
+        provision = resourceDAO.findProvision(15L);
+        assertNotNull(provision);
+        assertFalse(virSchemaDAO.findByProvision(provision).isEmpty());
+        assertTrue(virSchemaDAO.findByProvision(provision).contains(virSchema));
+
+        MappingItem item = virSchema.asLinkingMappingItem();
+        assertNotNull(item);
+        assertEquals(IntMappingType.UserVirtualSchema, item.getIntMappingType());
+        assertEquals(virSchema.getKey(), item.getIntAttrName());
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 7ee8002..96e606f 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -326,9 +326,6 @@ under the License.
   <DerSchema name="cn" expression="surname + ', ' + firstname" anyTypeClass_name="minimal user"/>
   <DerSchema name="noschema" expression="surname + ', ' + notfound" anyTypeClass_name="other"/>
 
-  <VirSchema name="virtualdata" anyTypeClass_name="minimal user"/>
-  <VirSchema name="virtualReadOnly" READONLY="1"  anyTypeClass_name="minimal user"/>
-
   <PlainSchema name="icon" type="String" anyTypeClass_name="minimal group"
                mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>                
   <PlainSchema name="show" type="Boolean" anyTypeClass_name="minimal group"
@@ -347,8 +344,6 @@ under the License.
   <DerSchema name="rderToBePropagated" expression="rderived_sx + '-' + rderived_dx"
              anyTypeClass_name="minimal group"/>
 
-  <VirSchema name="rvirtualdata" anyTypeClass_name="minimal group"/>
-
   <DerSchema name="rderivedschema" expression="rderived_sx + '-' + rderived_dx"  anyTypeClass_name="minimal group"/>
 
   <PlainSchema name="subscriptionDate" type="Date" anyTypeClass_name="generic membership"
@@ -364,8 +359,6 @@ under the License.
   <DerSchema name="mderiveddata" expression="mderived_sx + '-' + mderived_dx"/>
   <DerSchema name="mderToBePropagated" expression="mderived_sx + '-' + mderived_dx" 
              anyTypeClass_name="generic membership"/>
-
-  <VirSchema name="mvirtualdata"/>
         
   <PlainSchema name="model" type="String" anyTypeClass_name="minimal printer"
                mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
@@ -444,8 +437,6 @@ under the License.
   <UPlainAttrValue id="36" attribute_id="125" stringValue="vivaldi@syncope.org"/>
   <UPlainAttr id="126" owner_id="3" schema_name="type"/>
   <UPlainAttrValue id="37" attribute_id="126" stringValue="F"/>
-    
-  <UVirAttr id="100" schema_name="virtualdata" owner_id="3"/>
   
   <UDerAttr id="100" schema_name="cn" owner_id="3"/>
   <UDerAttr id="101" schema_name="cn" owner_id="1"/>
@@ -485,8 +476,6 @@ under the License.
 
   <GDerAttr id="103" owner_id="1" schema_name="rderToBePropagated"/>    
 
-  <GVirAttr id="98" owner_id="4" schema_name="rvirtualdata"/>
-
   <ConnInstance id="100" displayName="ConnInstance100"
                 location="${connid.location}"
                 bundleName="net.tirasa.connid.bundles.soap"
@@ -763,7 +752,7 @@ under the License.
                connObjectKey="0" password="0" purpose="BOTH"/>
   <MappingItem id="110" extAttrName="name" mapping_id="1"
                intAttrName="virtualdata" intMappingType="UserVirtualSchema" mandatoryCondition="type == 'F'"
-               connObjectKey="0" password="0" purpose="BOTH"/>
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
   <MappingItem id="111" extAttrName="fullname" mapping_id="1"
                intAttrName="cn" intMappingType="UserDerivedSchema" mandatoryCondition="true"
                connObjectKey="0" password="0" purpose="BOTH"/>
@@ -892,9 +881,6 @@ under the License.
   <MappingItem id="318" connObjectKey="0" password="0" mapping_id="11"
                extAttrName="mail" intAttrName="userId" intMappingType="UserPlainSchema"
                mandatoryCondition="false" purpose="BOTH"/>
-  <MappingItem id="319" connObjectKey="0" password="0" mapping_id="11"
-               extAttrName="givenname" intAttrName="virtualReadOnly" intMappingType="UserVirtualSchema"
-               mandatoryCondition="false" purpose="BOTH"/>
   <MappingItem id="320" connObjectKey="0" password="0" mapping_id="11"
                extAttrName="registeredAddress" intAttrName="obscure" intMappingType="UserPlainSchema"
                mandatoryCondition="false" purpose="BOTH"/>
@@ -902,6 +888,9 @@ under the License.
                extAttrName="jpegPhoto" intAttrName="photo" intMappingType="UserPlainSchema"
                mandatoryCondition="false" purpose="BOTH"/>
         
+  <VirSchema name="virtualReadOnly" READONLY="1" anyTypeClass_name="minimal user"
+             provision_id="11" extAttrName="givenname"/>
+
   <Provision id="20" resource_name="resource-ldap" anyType_name="GROUP" objectClass="__GROUP__"/>
   <Mapping id="20" provision_id="20"
            connObjectLink="&apos;cn=&apos; + name + &apos;,ou=groups,o=isp&apos;"/>
@@ -914,10 +903,9 @@ under the License.
   <MappingItem id="3" connObjectKey="0" password="0" mapping_id="20"
                extAttrName="description" intAttrName="title" intMappingType="GroupPlainSchema"
                mandatoryCondition="false" purpose="BOTH"/>
-  <MappingItem id="4" extAttrName="businessCategory" mapping_id="20"
-               intAttrName="rvirtualdata" intMappingType="GroupVirtualSchema" mandatoryCondition="false"
-               connObjectKey="0" password="0" purpose="BOTH"/>
   
+  <VirSchema name="rvirtualdata" anyTypeClass_name="minimal group" provision_id="20" extAttrName="businessCategory"/>
+
   <Provision id="16" resource_name="resource-db-sync" anyType_name="USER" objectClass="__ACCOUNT__"/>
   <Mapping id="16" provision_id="16"/>
   <MappingItem id="322" connObjectKey="0" mapping_id="16"
@@ -944,10 +932,9 @@ under the License.
   <MappingItem id="331" mapping_id="17" connObjectKey="1" password="0"
                extAttrName="id" intMappingType="UserKey" 
                mandatoryCondition="true" purpose="BOTH"/>
-  <MappingItem id="332" mapping_id="17" connObjectKey="0" password="0" 
-               extAttrName="USERNAME" intAttrName="virtualdata" intMappingType="UserVirtualSchema"
-               mandatoryCondition="false" purpose="BOTH"/>
                 
+  <VirSchema name="virtualdata" anyTypeClass_name="minimal user" provision_id="17" extAttrName="USERNAME"/>
+  
   <Provision id="18" resource_name="ws-target-resource-timeout" anyType_name="USER" objectClass="__ACCOUNT__"/>
   <Mapping id="18" provision_id="18"/>
   <MappingItem id="333" mapping_id="18" connObjectKey="1" password="0"

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
index 1be141f..ce8adba 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
@@ -18,7 +18,7 @@
  */
 package org.apache.syncope.core.provisioning.api;
 
-import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import org.apache.syncope.common.lib.types.ResourceOperation;
@@ -59,10 +59,11 @@ public interface Connector {
      * @param propagationAttempted if creation is actually performed (based on connector instance's capabilities)
      * @return Uid for created object
      */
-    Uid create(ObjectClass objectClass,
+    Uid create(
+            ObjectClass objectClass,
             Set<Attribute> attrs,
             OperationOptions options,
-            Set<String> propagationAttempted);
+            Boolean[] propagationAttempted);
 
     /**
      * Update user / group on a connector instance.
@@ -71,14 +72,15 @@ public interface Connector {
      * @param uid user to be updated
      * @param attrs attributes for update
      * @param options ConnId's OperationOptions
-     * @param propagationAttempted if update is actually performed (based on connector instance's capabilities)
+     * @param propagationAttempted if creation is actually performed (based on connector instance's capabilities)
      * @return Uid for updated object
      */
-    Uid update(ObjectClass objectClass,
+    Uid update(
+            ObjectClass objectClass,
             Uid uid,
             Set<Attribute> attrs,
             OperationOptions options,
-            Set<String> propagationAttempted);
+            Boolean[] propagationAttempted);
 
     /**
      * Delete user / group on a connector instance.
@@ -88,8 +90,11 @@ public interface Connector {
      * @param options ConnId's OperationOptions
      * @param propagationAttempted if deletion is actually performed (based on connector instance's capabilities)
      */
-    void delete(ObjectClass objectClass,
-            Uid uid, OperationOptions options, Set<String> propagationAttempted);
+    void delete(
+            ObjectClass objectClass,
+            Uid uid,
+            OperationOptions options,
+            Boolean[] propagationAttempted);
 
     /**
      * Fetches all remote objects (for use during full reconciliation).
@@ -169,6 +174,7 @@ public interface Connector {
      * query results
      * @param orderBy the sort keys which should be used for ordering the {@link ConnectorObject} returned by
      * search request
+     * @param mapItems mapping items
      */
     void search(
             ObjectClass objectClass,
@@ -176,7 +182,8 @@ public interface Connector {
             ResultsHandler handler,
             int pageSize,
             String pagedResultsCookie,
-            List<OrderByClause> orderBy);
+            List<OrderByClause> orderBy,
+            Iterator<? extends MappingItem> mapItems);
 
     /**
      * Read attribute for a given connector object.
@@ -238,5 +245,5 @@ public interface Connector {
      * @return options for requesting all mapped connector attributes
      * @see OperationOptions
      */
-    OperationOptions getOperationOptions(Collection<? extends MappingItem> mapItems);
+    OperationOptions getOperationOptions(Iterator<? extends MappingItem> mapItems);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
index 95e751e..2e31204 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
@@ -18,56 +18,32 @@
  */
 package org.apache.syncope.core.provisioning.api;
 
-import java.util.Collection;
-import org.apache.syncope.common.lib.patch.AttrPatch;
-import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.IntMappingType;
-import org.apache.syncope.common.lib.types.PropagationByResource;
+import java.util.List;
+import java.util.Map;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
-import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 
 public interface VirAttrHandler {
 
     /**
-     * Create and add virtual attributes to any.
+     * Query external resource (or cache, if configured) associated to the given any for values associated to the given
+     * virtual schema.
      *
-     * @param any any
-     * @param vAttrs virtual attributes to be added.
-     */
-    void createVirtual(Any any, Collection<AttrTO> vAttrs);
-
-    /**
-     * Update virtual attributes to any.
-     *
-     * @param any
-     * @param vAttrs virtual attributes to be updated.
-     * @return operations to be performed on external resources for virtual attributes changes
-     */
-    PropagationByResource updateVirtual(Any any, Collection<AttrPatch> vAttrs);
-
-    /**
-     * Update virtual attributes to any identified by the given {@code key}.
-     *
-     * @param key any key
-     * @param anyTypeKind type kind
-     * @param vAttrs virtual attributes to be updated.
-     * @return operations to be performed on external resources for virtual attributes changes
+     * @param any any object
+     * @param schema virtual schema
+     * @return virtual attribute values, either for local cache or external resource, if resource is owned by the given
+     * any and associated to the given virtual schema; empty list otherwise.
      */
-    PropagationByResource updateVirtual(Long key, AnyTypeKind anyTypeKind, Collection<AttrPatch> vAttrs);
-
-    VirSchema getVirSchema(String virSchemaName);
+    List<String> getValues(Any<?, ?> any, VirSchema schema);
 
     /**
-     * Query connected external resources for values to populated virtual attributes associated with the given owner.
+     * Query external resources (or cache, if configured) associated to the given any for values associated to all
+     * {@link VirSchema} instances in the {@link org.apache.syncope.core.persistence.api.entity.AnyTypeClass}
+     * associated to the given any.
      *
      * @param any any object
+     * @return virtual attribute values, either for local cache or external resources
      */
-    void retrieveVirAttrValues(Any<?, ?, ?> any);
-
-    void updateOnResourcesIfMappingMatches(
-            Any<?, ?, ?> any, String schemaKey, Iterable<? extends ExternalResource> resources,
-            IntMappingType mappingType, PropagationByResource propByRes);
+    Map<VirSchema, List<String>> getValues(Any<?, ?> any);
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/cache/VirAttrCacheValue.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/cache/VirAttrCacheValue.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/cache/VirAttrCacheValue.java
index 3288432..93b9c63 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/cache/VirAttrCacheValue.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/cache/VirAttrCacheValue.java
@@ -18,12 +18,10 @@
  */
 package org.apache.syncope.core.provisioning.api.cache;
 
-import java.util.Collections;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.List;
 
 /**
  * Cache entry value.
@@ -33,7 +31,7 @@ public class VirAttrCacheValue {
     /**
      * Virtual attribute values.
      */
-    private final Map<String, Set<String>> values;
+    private final List<String> values;
 
     /**
      * Entry creation date.
@@ -48,11 +46,17 @@ public class VirAttrCacheValue {
     public VirAttrCacheValue() {
         this.creationDate = new Date();
         this.lastAccessDate = new Date();
-        this.values = new HashMap<>();
+        this.values = new ArrayList<>();
     }
 
-    public void setResourceValues(final String resourceName, final Set<String> cached) {
-        this.values.put(resourceName, cached);
+    public void setValues(final Collection<Object> values) {
+        this.values.clear();
+
+        if (values != null) {
+            for (Object value : values) {
+                this.values.add(value.toString());
+            }
+        }
     }
 
     public Date getCreationDate() {
@@ -63,18 +67,8 @@ public class VirAttrCacheValue {
         creationDate = new Date(0);
     }
 
-    public Set<String> getValues(final String resourceName) {
-        return values.get(resourceName);
-    }
-
-    public Set<String> getValues() {
-        final Set<String> res = new HashSet<>();
-
-        for (Set<String> value : values.values()) {
-            res.addAll(value);
-        }
-
-        return Collections.unmodifiableSet(res);
+    public List<String> getValues() {
+        return values;
     }
 
     public Date getLastAccessDate() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationManager.java
index ef9baf2..dd87d19 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationManager.java
@@ -21,7 +21,6 @@ package org.apache.syncope.core.provisioning.api.propagation;
 import java.util.Collection;
 import java.util.List;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
@@ -75,7 +74,7 @@ public interface PropagationManager {
      * @param changePwd whether password should be included for propagation attributes or not
      * @param enable whether any object should be enabled or not, may be null to leave unchanged
      * @param propByRes operation to be performed per resource
-     * @param vAttrs virtual attributes patches
+     * @param vAttrs virtual attributes to be set
      * @param noPropResourceNames external resource names not to be considered for propagation
      * @return list of propagation tasks
      */
@@ -85,7 +84,7 @@ public interface PropagationManager {
             boolean changePwd,
             Boolean enable,
             PropagationByResource propByRes,
-            Collection<AttrPatch> vAttrs,
+            Collection<AttrTO> vAttrs,
             Collection<String> noPropResourceNames);
 
     /**

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/sync/PushActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/sync/PushActions.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/sync/PushActions.java
index 8f34331..c06a05f 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/sync/PushActions.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/sync/PushActions.java
@@ -37,7 +37,7 @@ public interface PushActions extends ProvisioningActions {
      * @return any.
      * @throws JobExecutionException in case of generic failure
      */
-    <A extends Any<?, ?, ?>> A beforeAssign(
+    <A extends Any<?, ?>> A beforeAssign(
             ProvisioningProfile<?, ?> profile,
             A any) throws JobExecutionException;
 
@@ -50,7 +50,7 @@ public interface PushActions extends ProvisioningActions {
      * @return any.
      * @throws JobExecutionException in case of generic failure
      */
-    <A extends Any<?, ?, ?>> A beforeProvision(
+    <A extends Any<?, ?>> A beforeProvision(
             ProvisioningProfile<?, ?> profile,
             A any) throws JobExecutionException;
 
@@ -63,7 +63,7 @@ public interface PushActions extends ProvisioningActions {
      * @return any.
      * @throws JobExecutionException in case of generic failure
      */
-    <A extends Any<?, ?, ?>> A beforeUpdate(
+    <A extends Any<?, ?>> A beforeUpdate(
             ProvisioningProfile<?, ?> profile,
             A any) throws JobExecutionException;
 
@@ -76,7 +76,7 @@ public interface PushActions extends ProvisioningActions {
      * @return any.
      * @throws JobExecutionException in case of generic failure
      */
-    <A extends Any<?, ?, ?>> A beforeLink(
+    <A extends Any<?, ?>> A beforeLink(
             ProvisioningProfile<?, ?> profile,
             A any) throws JobExecutionException;
 
@@ -89,7 +89,7 @@ public interface PushActions extends ProvisioningActions {
      * @return any.
      * @throws JobExecutionException in case of generic failure
      */
-    <A extends Any<?, ?, ?>> A beforeUnlink(
+    <A extends Any<?, ?>> A beforeUnlink(
             ProvisioningProfile<?, ?> profile,
             A any) throws JobExecutionException;
 
@@ -102,7 +102,7 @@ public interface PushActions extends ProvisioningActions {
      * @return any.
      * @throws JobExecutionException in case of generic failure
      */
-    <A extends Any<?, ?, ?>> A beforeUnassign(
+    <A extends Any<?, ?>> A beforeUnassign(
             ProvisioningProfile<?, ?> profile,
             A any) throws JobExecutionException;
 
@@ -115,7 +115,7 @@ public interface PushActions extends ProvisioningActions {
      * @return any.
      * @throws JobExecutionException in case of generic failure
      */
-    <A extends Any<?, ?, ?>> A beforeDeprovision(
+    <A extends Any<?, ?>> A beforeDeprovision(
             ProvisioningProfile<?, ?> profile,
             A any) throws JobExecutionException;
 
@@ -128,7 +128,7 @@ public interface PushActions extends ProvisioningActions {
      * @return any.
      * @throws JobExecutionException in case of generic failure
      */
-    <A extends Any<?, ?, ?>> A beforeDelete(
+    <A extends Any<?, ?>> A beforeDelete(
             ProvisioningProfile<?, ?> profile,
             A any) throws JobExecutionException;
 
@@ -142,7 +142,7 @@ public interface PushActions extends ProvisioningActions {
      * @param error error being reported
      * @throws JobExecutionException in case of generic failure
      */
-    <A extends Any<?, ?, ?>> void onError(
+    <A extends Any<?, ?>> void onError(
             ProvisioningProfile<?, ?> profile,
             A any,
             ProvisioningResult result,
@@ -157,7 +157,7 @@ public interface PushActions extends ProvisioningActions {
      * @param result operation result.
      * @throws JobExecutionException in case of generic failure
      */
-    <A extends Any<?, ?, ?>> void after(
+    <A extends Any<?, ?>> void after(
             ProvisioningProfile<?, ?> profile,
             A any,
             ProvisioningResult result) throws JobExecutionException;

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
index a28f44e..6c2be32 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
@@ -21,8 +21,8 @@ package org.apache.syncope.core.provisioning.java;
 import java.io.File;
 import java.net.URI;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Future;
@@ -31,6 +31,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
 import org.apache.syncope.common.lib.types.ConnectorCapability;
+import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
@@ -168,12 +169,12 @@ public class ConnectorFacadeProxy implements Connector {
             final ObjectClass objectClass,
             final Set<Attribute> attrs,
             final OperationOptions options,
-            final Set<String> propagationAttempted) {
+            final Boolean[] propagationAttempted) {
 
         Uid result = null;
 
         if (activeConnInstance.getCapabilities().contains(ConnectorCapability.CREATE)) {
-            propagationAttempted.add("create");
+            propagationAttempted[0] = true;
 
             Future<Uid> future = asyncFacade.create(connector, objectClass, attrs, options);
             try {
@@ -203,12 +204,12 @@ public class ConnectorFacadeProxy implements Connector {
             final Uid uid,
             final Set<Attribute> attrs,
             final OperationOptions options,
-            final Set<String> propagationAttempted) {
+            final Boolean[] propagationAttempted) {
 
         Uid result = null;
 
         if (activeConnInstance.getCapabilities().contains(ConnectorCapability.UPDATE)) {
-            propagationAttempted.add("update");
+            propagationAttempted[0] = true;
 
             Future<Uid> future = asyncFacade.update(connector, objectClass, uid, attrs, options);
 
@@ -239,10 +240,10 @@ public class ConnectorFacadeProxy implements Connector {
             final ObjectClass objectClass,
             final Uid uid,
             final OperationOptions options,
-            final Set<String> propagationAttempted) {
+            final Boolean[] propagationAttempted) {
 
         if (activeConnInstance.getCapabilities().contains(ConnectorCapability.DELETE)) {
-            propagationAttempted.add("delete");
+            propagationAttempted[0] = true;
 
             Future<Uid> future = asyncFacade.delete(connector, objectClass, uid, options);
 
@@ -544,7 +545,8 @@ public class ConnectorFacadeProxy implements Connector {
             final ResultsHandler handler,
             final int pageSize,
             final String pagedResultsCookie,
-            final List<OrderByClause> orderBy) {
+            final List<OrderByClause> orderBy,
+            final Iterator<? extends MappingItem> mapItems) {
 
         OperationOptionsBuilder builder = new OperationOptionsBuilder().setPageSize(pageSize);
         if (pagedResultsCookie != null) {
@@ -558,6 +560,8 @@ public class ConnectorFacadeProxy implements Connector {
             }
         }, new ArrayList<SortKey>(orderBy.size())));
 
+        builder.setAttributesToGet(getOperationOptions(mapItems).getAttributesToGet());
+
         search(objectClass, filter, handler, builder.build());
     }
 
@@ -567,7 +571,7 @@ public class ConnectorFacadeProxy implements Connector {
     }
 
     @Override
-    public OperationOptions getOperationOptions(final Collection<? extends MappingItem> mapItems) {
+    public OperationOptions getOperationOptions(final Iterator<? extends MappingItem> mapItems) {
         // -------------------------------------
         // Ask just for mapped attributes
         // -------------------------------------
@@ -578,8 +582,11 @@ public class ConnectorFacadeProxy implements Connector {
         attrsToGet.add(Uid.NAME);
         attrsToGet.add(OperationalAttributes.ENABLE_NAME);
 
-        for (MappingItem item : mapItems) {
-            attrsToGet.add(item.getExtAttrName());
+        while (mapItems.hasNext()) {
+            MappingItem mapItem = mapItems.next();
+            if (mapItem.getPurpose() != MappingPurpose.NONE) {
+                attrsToGet.add(mapItem.getExtAttrName());
+            }
         }
 
         builder.setAttributesToGet(attrsToGet);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
index d332e23..ffecdb9 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
@@ -105,17 +105,6 @@ public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisionin
 
         WorkflowResult<Long> updated = awfAdapter.update(anyObjectPatch);
 
-        // SYNCOPE-459: take care of user virtual attributes ...
-        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                updated.getResult(),
-                AnyTypeKind.ANY_OBJECT,
-                anyObjectPatch.getVirAttrs());
-        if (updated.getPropByRes() == null) {
-            updated.setPropByRes(propByResVirAttr);
-        } else {
-            updated.getPropByRes().merge(propByResVirAttr);
-        }
-
         List<PropagationTask> tasks = propagationManager.getUpdateTasks(
                 AnyTypeKind.ANY_OBJECT,
                 updated.getResult(),
@@ -124,7 +113,6 @@ public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisionin
                 updated.getPropByRes(),
                 anyObjectPatch.getVirAttrs(),
                 excludedResources);
-
         PropagationReporter propagationReporter =
                 ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
         try {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
index 0fff2a3..9e3d566 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
@@ -137,17 +137,6 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
 
         WorkflowResult<Long> updated = gwfAdapter.update(groupPatch);
 
-        // SYNCOPE-459: take care of user virtual attributes ...
-        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                updated.getResult(),
-                AnyTypeKind.GROUP,
-                groupPatch.getVirAttrs());
-        if (updated.getPropByRes() == null) {
-            updated.setPropByRes(propByResVirAttr);
-        } else {
-            updated.getPropByRes().merge(propByResVirAttr);
-        }
-
         List<PropagationTask> tasks = propagationManager.getUpdateTasks(
                 AnyTypeKind.GROUP,
                 updated.getResult(),
@@ -156,7 +145,6 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
                 updated.getPropByRes(),
                 groupPatch.getVirAttrs(),
                 excludedResources);
-
         PropagationReporter propagationReporter =
                 ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
         try {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
index a59337c..5424486 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
@@ -119,28 +119,14 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
     public Pair<Long, List<PropagationStatus>> update(final UserPatch userPatch) {
         WorkflowResult<Pair<UserPatch, Boolean>> updated = uwfAdapter.update(userPatch);
 
-        // SYNCOPE-459: take care of user virtual attributes ...
-        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                updated.getResult().getKey().getKey(),
-                AnyTypeKind.USER,
-                userPatch.getVirAttrs());
-        if (updated.getPropByRes() == null) {
-            updated.setPropByRes(propByResVirAttr);
-        } else {
-            updated.getPropByRes().merge(propByResVirAttr);
-        }
-
         List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(updated);
-
-        PropagationReporter propagationReporter = ApplicationContextProvider.getBeanFactory().
-                getBean(PropagationReporter.class);
-        if (!tasks.isEmpty()) {
-            try {
-                taskExecutor.execute(tasks, propagationReporter);
-            } catch (PropagationException e) {
-                LOG.error("Error propagation primary resource", e);
-                propagationReporter.onPrimaryResourceFailure(tasks);
-            }
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
         }
 
         return new ImmutablePair<>(updated.getResult().getKey().getKey(), propagationReporter.getStatuses());
@@ -291,7 +277,6 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
                 propByRes,
                 null,
                 null);
-
         PropagationReporter propReporter =
                 ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
         try {
@@ -302,7 +287,6 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
         }
 
         return propReporter.getStatuses();
-
     }
 
     @Override


[17/54] [abbrv] syncope git commit: Upgrading surefire, failsafe and checkstyle plugins

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
index 409a16b,0000000..24cd09d
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
@@@ -1,570 -1,0 +1,570 @@@
 +/*
 + * 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.console.topology;
 +
 +import java.io.Serializable;
 +import java.net.URI;
 +import java.util.ArrayList;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Locale;
 +import java.util.Map;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.cxf.jaxrs.client.WebClient;
 +import org.apache.syncope.client.console.SyncopeConsoleSession;
 +import org.apache.syncope.client.console.pages.BasePage;
 +import org.apache.syncope.client.console.panels.AbstractResourceModal.CreateEvent;
 +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
 +import org.apache.syncope.common.lib.to.ConnInstanceTO;
 +import org.apache.syncope.common.lib.to.ResourceTO;
 +import org.apache.syncope.common.lib.types.Entitlement;
 +import org.apache.syncope.common.rest.api.service.SyncopeService;
 +import org.apache.wicket.Component;
 +import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
 +import org.apache.wicket.ajax.AjaxRequestTarget;
 +import org.apache.wicket.ajax.IAjaxIndicatorAware;
 +import org.apache.wicket.behavior.Behavior;
 +import org.apache.wicket.event.IEvent;
 +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 +import org.apache.wicket.markup.head.IHeaderResponse;
 +import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
 +import org.apache.wicket.markup.html.WebMarkupContainer;
 +import org.apache.wicket.markup.html.list.ListItem;
 +import org.apache.wicket.markup.html.list.ListView;
 +import org.apache.wicket.model.LoadableDetachableModel;
 +import org.apache.wicket.util.time.Duration;
 +
 +public class Topology extends BasePage {
 +
 +    private static final long serialVersionUID = -1100228004207271272L;
 +
 +    public static final String CONNECTOR_SERVER_LOCATION_PREFIX = "connid://";
 +
 +    public static final String ROOT_NAME = "Syncope";
 +
 +    private final int origX = 3100;
 +
 +    private final int origY = 2800;
 +
 +    private static final int RESOURCE_MODAL_WIN_HEIGHT = 700;
 +
 +    private static final int RESOURCE_MODAL_WIN_WIDTH = 1000;
 +
 +    private final ModalWindow modal;
 +
 +    private final WebMarkupContainer newlyCreatedContainer;
 +
 +    private final ListView<TopologyNode> newlyCreated;
 +
 +    private final LoadableDetachableModel<List<ResourceTO>> resModel = new LoadableDetachableModel<List<ResourceTO>>() {
 +
 +        private static final long serialVersionUID = 5275935387613157431L;
 +
 +        @Override
 +        protected List<ResourceTO> load() {
 +            final List<ResourceTO> result = resourceRestClient.getAll();
 +            return result;
 +        }
 +    };
 +
 +    private final LoadableDetachableModel<Map<String, List<ConnInstanceTO>>> connModel
 +            = new LoadableDetachableModel<Map<String, List<ConnInstanceTO>>>() {
 +
 +                private static final long serialVersionUID = 5275935387613157432L;
 +
 +                @Override
 +                protected Map<String, List<ConnInstanceTO>> load() {
 +                    final Map<String, List<ConnInstanceTO>> res = new HashMap<>();
 +
 +                    for (ConnInstanceTO conn : connectorRestClient.getAllConnectors()) {
 +                        final List<ConnInstanceTO> conns;
 +                        if (res.containsKey(conn.getLocation())) {
 +                            conns = res.get(conn.getLocation());
 +                        } else {
 +                            conns = new ArrayList<>();
 +                            res.put(conn.getLocation(), conns);
 +                        }
 +                        conns.add(conn);
 +                    }
 +
 +                    return res;
 +                }
 +            };
 +
 +    private final LoadableDetachableModel<Pair<List<URI>, List<URI>>> csModel
 +            = new LoadableDetachableModel<Pair<List<URI>, List<URI>>>() {
 +
 +                private static final long serialVersionUID = 5275935387613157433L;
 +
 +                @Override
 +                protected Pair<List<URI>, List<URI>> load() {
 +                    final List<URI> connectorServers = new ArrayList<>();
 +                    final List<URI> filePaths = new ArrayList<>();
 +
 +                    for (String location : SyncopeConsoleSession.get().getSyncopeTO().getConnIdLocations()) {
 +                        if (location.startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) {
 +                            connectorServers.add(URI.create(location));
 +                        } else {
 +                            filePaths.add(URI.create(location));
 +                        }
 +                    }
 +
 +                    return Pair.of(connectorServers, filePaths);
 +                }
 +            };
 +
 +    protected enum SupportedOperation {
 +
 +        CHECK_RESOURCE,
 +        CHECK_CONNECTOR,
 +        ADD_ENDPOINT;
 +
 +    }
 +
 +    public Topology() {
 +        modal = new ModalWindow("modal");
 +        add(modal);
 +
 +        modal.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
 +        modal.setInitialHeight(RESOURCE_MODAL_WIN_HEIGHT);
 +        modal.setInitialWidth(RESOURCE_MODAL_WIN_WIDTH);
 +        modal.setCookieName("resource-modal");
 +
 +        add(new WebSocketBehavior());
 +
 +        // -----------------------------------------
 +        // Add Zoom panel
 +        // -----------------------------------------
 +        final ActionLinksPanel.Builder<Serializable> zoomActionPanel = ActionLinksPanel.builder(getPageReference());
 +        zoomActionPanel.setDisableIndicator(true);
 +
 +        zoomActionPanel.add(new ActionLink<Serializable>() {
 +
 +            private static final long serialVersionUID = -3722207913631435501L;
 +
 +            @Override
 +            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                target.appendJavaScript("zoomIn($('#drawing')[0]);");
 +            }
 +        }, ActionLink.ActionType.ZOOM_IN, Entitlement.RESOURCE_LIST).add(new ActionLink<Serializable>() {
 +
 +            private static final long serialVersionUID = -3722207913631435501L;
 +
 +            @Override
 +            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
 +                target.appendJavaScript("zoomOut($('#drawing')[0]);");
 +            }
 +        }, ActionLink.ActionType.ZOOM_OUT, Entitlement.RESOURCE_LIST);
 +
 +        add(zoomActionPanel.build("zoom"));
 +        // -----------------------------------------
 +
 +        // -----------------------------------------
 +        // Add Syncope (root topologynode)
 +        // -----------------------------------------
 +        final TopologyNode syncopeTopologyNode = new TopologyNode(ROOT_NAME, ROOT_NAME, TopologyNode.Kind.SYNCOPE);
 +        syncopeTopologyNode.setX(origX);
 +        syncopeTopologyNode.setY(origY);
 +
 +        final URI uri = WebClient.client(SyncopeConsoleSession.get().getService(SyncopeService.class)).getBaseURI();
 +        syncopeTopologyNode.setHost(uri.getHost());
 +        syncopeTopologyNode.setPort(uri.getPort());
 +
 +        add(topologyNodePanel("syncope", syncopeTopologyNode));
 +
 +        final Map<Serializable, Map<Serializable, TopologyNode>> connections = new HashMap<>();
 +        final Map<Serializable, TopologyNode> syncopeConnections = new HashMap<>();
 +        connections.put(syncopeTopologyNode.getKey(), syncopeConnections);
 +
 +        // required to retrieve parent positions
 +        final Map<String, TopologyNode> servers = new HashMap<>();
 +        final Map<Long, TopologyNode> connectors = new HashMap<>();
 +        // -----------------------------------------
 +
 +        // -----------------------------------------
 +        // Add Connector Servers
 +        // -----------------------------------------
 +        final ListView<URI> connectorServers = new ListView<URI>("connectorServers", csModel.getObject().getLeft()) {
 +
 +            private static final long serialVersionUID = 6978621871488360380L;
 +
 +            private final int size = csModel.getObject().getLeft().size() + 1;
 +
 +            @Override
 +            protected void populateItem(final ListItem<URI> item) {
 +                int kx = size >= 4 ? 800 : (200 * size);
 +
 +                int x = (int) Math.round(origX + kx * Math.cos(Math.PI + Math.PI * (item.getIndex() + 1) / size));
 +                int y = (int) Math.round(origY + 100 * Math.sin(Math.PI + Math.PI * (item.getIndex() + 1) / size));
 +
 +                final URI location = item.getModelObject();
 +                final String url = location.toASCIIString();
 +
 +                final TopologyNode topologynode = new TopologyNode(url, url, TopologyNode.Kind.CONNECTOR_SERVER);
 +
 +                topologynode.setHost(location.getHost());
 +                topologynode.setPort(location.getPort());
 +                topologynode.setX(x);
 +                topologynode.setY(y);
 +
 +                servers.put(String.class.cast(topologynode.getKey()), topologynode);
 +
 +                item.add(topologyNodePanel("cs", topologynode));
 +
 +                syncopeConnections.put(url, topologynode);
 +                connections.put(url, new HashMap<Serializable, TopologyNode>());
 +            }
 +        };
 +
 +        connectorServers.setOutputMarkupId(true);
 +        add(connectorServers);
 +        // -----------------------------------------
 +
 +        // -----------------------------------------
 +        // Add File Paths
 +        // -----------------------------------------
 +        final ListView<URI> filePaths = new ListView<URI>("filePaths", csModel.getObject().getRight()) {
 +
 +            private static final long serialVersionUID = 6978621871488360380L;
 +
 +            private final int size = csModel.getObject().getRight().size() + 1;
 +
 +            @Override
 +            protected void populateItem(final ListItem<URI> item) {
 +                int kx = size >= 4 ? 800 : (200 * size);
 +
 +                int x = (int) Math.round(origX + kx * Math.cos(Math.PI * (item.getIndex() + 1) / size));
 +                int y = (int) Math.round(origY + 100 * Math.sin(Math.PI * (item.getIndex() + 1) / size));
 +
 +                final URI location = item.getModelObject();
 +                final String url = location.toASCIIString();
 +
 +                final TopologyNode topologynode = new TopologyNode(url, url, TopologyNode.Kind.FS_PATH);
 +
 +                topologynode.setHost(location.getHost());
 +                topologynode.setPort(location.getPort());
 +                topologynode.setX(x);
 +                topologynode.setY(y);
 +
 +                servers.put(String.class.cast(topologynode.getKey()), topologynode);
 +
 +                item.add(topologyNodePanel("fp", topologynode));
 +
 +                syncopeConnections.put(url, topologynode);
 +                connections.put(url, new HashMap<Serializable, TopologyNode>());
 +            }
 +        };
 +
 +        filePaths.setOutputMarkupId(true);
 +        add(filePaths);
 +        // -----------------------------------------
 +
 +        // -----------------------------------------
 +        // Add Connector Intances
 +        // -----------------------------------------
 +        final List<List<ConnInstanceTO>> allConns = new ArrayList<>(connModel.getObject().values());
 +
 +        final ListView<List<ConnInstanceTO>> conns = new ListView<List<ConnInstanceTO>>("conns", allConns) {
 +
 +            private static final long serialVersionUID = 697862187148836036L;
 +
 +            @Override
 +            protected void populateItem(final ListItem<List<ConnInstanceTO>> item) {
 +
 +                final int size = item.getModelObject().size() + 1;
 +
 +                final ListView<ConnInstanceTO> conns = new ListView<ConnInstanceTO>("conns", item.getModelObject()) {
 +
 +                    private static final long serialVersionUID = 6978621871488360381L;
 +
 +                    @Override
 +                    protected void populateItem(final ListItem<ConnInstanceTO> item) {
 +                        final ConnInstanceTO conn = item.getModelObject();
 +
 +                        final TopologyNode topologynode = new TopologyNode(
 +                                Long.valueOf(conn.getKey()), conn.getDisplayName(), TopologyNode.Kind.CONNECTOR);
 +
 +                        // Define the parent note
 +                        final TopologyNode parent = servers.get(conn.getLocation());
 +
 +                        // Set the position
 +                        int kx = size >= 6 ? 800 : (130 * size);
 +
 +                        final double hpos;
 +                        if (conn.getLocation().startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) {
 +                            hpos = Math.PI;
 +                        } else {
 +                            hpos = 0.0;
 +                        }
 +
 +                        int x = (int) Math.round((parent == null ? origX : parent.getX())
 +                                + kx * Math.cos(hpos + Math.PI * (item.getIndex() + 1) / size));
 +                        int y = (int) Math.round((parent == null ? origY : parent.getY())
 +                                + 100 * Math.sin(hpos + Math.PI * (item.getIndex() + 1) / size));
 +
 +                        topologynode.setConnectionDisplayName(conn.getBundleName());
 +                        topologynode.setX(x);
 +                        topologynode.setY(y);
 +
 +                        connectors.put(Long.class.cast(topologynode.getKey()), topologynode);
 +                        item.add(topologyNodePanel("conn", topologynode));
 +
 +                        // Update connections
 +                        final Map<Serializable, TopologyNode> remoteConnections;
 +
 +                        if (connections.containsKey(conn.getLocation())) {
 +                            remoteConnections = connections.get(conn.getLocation());
 +                        } else {
 +                            remoteConnections = new HashMap<>();
 +                            connections.put(conn.getLocation(), remoteConnections);
 +                        }
 +                        remoteConnections.put(conn.getKey(), topologynode);
 +                    }
 +                };
 +
 +                conns.setOutputMarkupId(true);
 +                item.add(conns);
 +            }
 +        };
 +
 +        conns.setOutputMarkupId(true);
 +        add(conns);
 +        // -----------------------------------------
 +
 +        // -----------------------------------------
 +        // Add Resources
 +        // -----------------------------------------
 +        final List<Long> connToBeProcessed = new ArrayList<>();
 +        for (ResourceTO resourceTO : resModel.getObject()) {
 +            final TopologyNode topologynode = new TopologyNode(
 +                    resourceTO.getKey(), resourceTO.getKey(), TopologyNode.Kind.RESOURCE);
 +
 +            final Map<Serializable, TopologyNode> remoteConnections;
 +
 +            if (connections.containsKey(resourceTO.getConnector())) {
 +                remoteConnections = connections.get(resourceTO.getConnector());
 +            } else {
 +                remoteConnections = new HashMap<>();
 +                connections.put(resourceTO.getConnector(), remoteConnections);
 +            }
 +
 +            remoteConnections.put(topologynode.getKey(), topologynode);
 +
 +            if (!connToBeProcessed.contains(resourceTO.getConnector())) {
 +                connToBeProcessed.add(resourceTO.getConnector());
 +            }
 +        }
 +
 +        final ListView<Long> resources = new ListView<Long>("resources", connToBeProcessed) {
 +
 +            private static final long serialVersionUID = 697862187148836038L;
 +
 +            @Override
 +            protected void populateItem(final ListItem<Long> item) {
 +                final Long connectorId = item.getModelObject();
 +
 +                final ListView<TopologyNode> innerListView = new ListView<TopologyNode>("resources",
 +                        new ArrayList<>(connections.get(connectorId).values())) {
 +
 +                            private static final long serialVersionUID = 1L;
 +
 +                            private final int size = getModelObject().size() + 1;
 +
 +                            @Override
 +                            protected void populateItem(final ListItem<TopologyNode> item) {
 +                                final TopologyNode topologynode = item.getModelObject();
 +                                final TopologyNode parent = connectors.get(connectorId);
 +
 +                                // Set position
 +                                int kx = size >= 16 ? 800 : (48 * size);
 +                                int ky = size < 4 ? 100 : size < 6 ? 350 : 750;
 +
 +                                final double hpos;
 +                                if (parent == null || parent.getY() < syncopeTopologyNode.getY()) {
 +                                    hpos = Math.PI;
 +                                } else {
 +                                    hpos = 0.0;
 +                                }
 +
 +                                int x = (int) Math.round((parent == null ? origX : parent.getX())
 +                                        + kx * Math.cos(hpos + Math.PI * (item.getIndex() + 1) / size));
 +                                int y = (int) Math.round((parent == null ? origY : parent.getY())
 +                                        + ky * Math.sin(hpos + Math.PI * (item.getIndex() + 1) / size));
 +
 +                                topologynode.setX(x);
 +                                topologynode.setY(y);
 +
 +                                item.add(topologyNodePanel("res", topologynode));
 +                            }
 +                        };
 +
 +                innerListView.setOutputMarkupId(true);
 +                item.add(innerListView);
 +            }
 +        };
 +
 +        resources.setOutputMarkupId(true);
 +        add(resources);
 +        // -----------------------------------------
 +
 +        // -----------------------------------------
 +        // Create connections
 +        // -----------------------------------------
 +        final WebMarkupContainer jsPlace = new WebMarkupContainerNoVeil("jsPlace");
 +        jsPlace.setOutputMarkupId(true);
 +        add(jsPlace);
 +
 +        jsPlace.add(new Behavior() {
 +
 +            private static final long serialVersionUID = 2661717818979056044L;
 +
 +            @Override
 +            public void renderHead(final Component component, final IHeaderResponse response) {
 +                final StringBuilder jsPlumbConf = new StringBuilder();
 +                jsPlumbConf.append(String.format(Locale.US, "activate(%.2f);", 0.68f));
 +
 +                for (String str : createConnections(connections)) {
 +                    jsPlumbConf.append(str);
 +                }
 +
 +                response.render(OnDomReadyHeaderItem.forScript(jsPlumbConf.toString()));
 +            }
 +        });
 +
 +        jsPlace.add(new AbstractAjaxTimerBehavior(Duration.seconds(2)) {
 +
 +            private static final long serialVersionUID = 1L;
 +
 +            @Override
 +            protected void onTimer(final AjaxRequestTarget target) {
 +                target.appendJavaScript("checkConnection()");
 +
 +                if (getUpdateInterval().seconds() < 5.0) {
 +                    setUpdateInterval(Duration.seconds(5));
 +                } else if (getUpdateInterval().seconds() < 10.0) {
 +                    setUpdateInterval(Duration.seconds(10));
 +                } else if (getUpdateInterval().seconds() < 15.0) {
 +                    setUpdateInterval(Duration.seconds(15));
 +                } else if (getUpdateInterval().seconds() < 20.0) {
 +                    setUpdateInterval(Duration.seconds(20));
 +                } else if (getUpdateInterval().seconds() < 30.0) {
 +                    setUpdateInterval(Duration.seconds(30));
 +                } else if (getUpdateInterval().seconds() < 60.0) {
 +                    setUpdateInterval(Duration.seconds(60));
 +                }
 +            }
 +        });
 +        // -----------------------------------------
 +
 +        newlyCreatedContainer = new WebMarkupContainer("newlyCreatedContainer");
 +        newlyCreatedContainer.setOutputMarkupId(true);
 +        add(newlyCreatedContainer);
 +
 +        newlyCreated = new ListView<TopologyNode>("newlyCreated", new ArrayList<TopologyNode>()) {
 +
 +            private static final long serialVersionUID = 1L;
 +
 +            @Override
 +            protected void populateItem(final ListItem<TopologyNode> item) {
 +                item.add(topologyNodePanel("el", item.getModelObject()));
 +            }
 +        };
 +        newlyCreated.setOutputMarkupId(true);
 +        newlyCreated.setReuseItems(true);
 +
 +        newlyCreatedContainer.add(newlyCreated);
 +    }
 +
 +    private List<String> createConnections(final Map<Serializable, Map<Serializable, TopologyNode>> targets) {
 +        List<String> list = new ArrayList<>();
 +
 +        for (Map.Entry<Serializable, Map<Serializable, TopologyNode>> source : targets.entrySet()) {
 +            for (Map.Entry<Serializable, TopologyNode> target : source.getValue().entrySet()) {
 +                list.add(String.format("connect('%s','%s','%s');",
 +                        source.getKey(),
 +                        target.getKey(),
 +                        target.getValue().getKind()));
 +            }
 +        }
 +        return list;
 +    }
 +
 +    private TopologyNodePanel topologyNodePanel(final String id, final TopologyNode node) {
 +
 +        final TopologyNodePanel panel = new TopologyNodePanel(id, node, getPageReference(), modal);
 +        panel.setMarkupId(String.valueOf(node.getKey()));
 +        panel.setOutputMarkupId(true);
 +
 +        panel.add(new Behavior() {
 +
 +            private static final long serialVersionUID = 1L;
 +
 +            @Override
 +            public void renderHead(final Component component, final IHeaderResponse response) {
 +                response.render(OnDomReadyHeaderItem.forScript(String.format("setPosition('%s', %d, %d)",
 +                        node.getKey(), node.getX(), node.getY())));
 +            }
 +        });
 +
 +        return panel;
 +    }
 +
 +    @Override
 +    @SuppressWarnings("unchecked")
 +    public void onEvent(final IEvent<?> event) {
 +        super.onEvent(event);
 +
 +        if (event.getPayload() instanceof CreateEvent) {
 +            final CreateEvent resourceCreateEvent = CreateEvent.class.cast(event.getPayload());
 +
 +            final TopologyNode node = new TopologyNode(
 +                    resourceCreateEvent.getKey(),
 +                    resourceCreateEvent.getDisplayName(),
 +                    resourceCreateEvent.getKind());
 +
 +            newlyCreated.getModelObject().add(node);
 +            resourceCreateEvent.getTarget().add(newlyCreatedContainer);
 +
 +            resourceCreateEvent.getTarget().appendJavaScript(String.format(
 +                    "window.Wicket.WebSocket.send('"
 +                    + "{\"kind\":\"%s\",\"target\":\"%s\",\"source\":\"%s\",\"scope\":\"%s\"}"
 +                    + "');",
 +                    SupportedOperation.ADD_ENDPOINT,
 +                    resourceCreateEvent.getKey(),
 +                    resourceCreateEvent.getParent(),
 +                    resourceCreateEvent.getKind()));
 +        }
 +    }
 +
 +    private static class WebMarkupContainerNoVeil extends WebMarkupContainer implements IAjaxIndicatorAware {
 +
 +        private static final long serialVersionUID = 1L;
 +
-         public WebMarkupContainerNoVeil(final String id) {
++        WebMarkupContainerNoVeil(final String id) {
 +            super(id);
 +        }
 +
 +        @Override
 +        public String getAjaxIndicatorMarkupId() {
 +            return StringUtils.EMPTY;
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/topology/WebSocketBehavior.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/topology/WebSocketBehavior.java
index 1b847f9,0000000..8e3267d
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/WebSocketBehavior.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/WebSocketBehavior.java
@@@ -1,208 -1,0 +1,208 @@@
 +/*
 + * 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.console.topology;
 +
 +import com.fasterxml.jackson.databind.JsonNode;
 +import com.fasterxml.jackson.databind.ObjectMapper;
 +import java.io.IOException;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.Map;
 +import java.util.Set;
 +import java.util.concurrent.ExecutorService;
 +import java.util.concurrent.Executors;
 +import org.apache.syncope.client.console.rest.ConnectorRestClient;
 +import org.apache.syncope.client.console.rest.ResourceRestClient;
 +import org.apache.syncope.common.lib.to.ConnInstanceTO;
 +import org.apache.syncope.common.lib.to.ResourceTO;
 +import org.apache.wicket.Application;
 +import org.apache.wicket.Session;
 +import org.apache.wicket.ThreadContext;
 +import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler;
 +import org.apache.wicket.protocol.ws.api.message.TextMessage;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +public class WebSocketBehavior extends org.apache.wicket.protocol.ws.api.WebSocketBehavior {
 +
 +    protected static final Logger LOG = LoggerFactory.getLogger(WebSocketBehavior.class);
 +
 +    private static final long serialVersionUID = -1653665542635275551L;
 +
 +    private final Map<String, String> resources = new HashMap<>();
 +
 +    private final Set<String> runningResCheck = new HashSet<>();
 +
 +    private final Map<Long, String> connectors = new HashMap<>();
 +
 +    private final Set<Long> runningConnCheck = new HashSet<>();
 +
 +    private final ConnectorRestClient connectorRestClient = new ConnectorRestClient();
 +
 +    private final ResourceRestClient resourceRestClient = new ResourceRestClient();
 +
 +    @Override
 +    protected void onMessage(final WebSocketRequestHandler handler, final TextMessage message) {
 +        try {
 +            final ObjectMapper mapper = new ObjectMapper();
 +            final JsonNode obj = mapper.readTree(message.getText());
 +
 +            final ExecutorService executorService = Executors.newFixedThreadPool(1);
 +
 +            switch (Topology.SupportedOperation.valueOf(obj.get("kind").asText())) {
 +                case CHECK_CONNECTOR:
 +                    final Long ckey = obj.get("target").asLong();
 +
 +                    if (connectors.containsKey(ckey)) {
 +                        handler.push(connectors.get(ckey));
 +                    } else {
 +                        handler.push(String.format(
 +                                "{ \"status\": \"%s\", \"target\": \"%s\"}", TopologyNode.Status.UNKNOWN, ckey));
 +                    }
 +
 +                    synchronized (runningConnCheck) {
 +                        if (runningConnCheck.contains(ckey)) {
 +                            LOG.debug("Running connection check for connector {}", ckey);
 +                        } else {
 +                            runningConnCheck.add(ckey);
 +                        }
 +                    }
 +
 +                    executorService.execute(new ConnCheck(ckey));
 +
 +                    break;
 +                case CHECK_RESOURCE:
 +                    final String rkey = obj.get("target").asText();
 +
 +                    if (resources.containsKey(rkey)) {
 +                        handler.push(resources.get(rkey));
 +                    } else {
 +                        handler.push(String.format(
 +                                "{ \"status\": \"%s\", \"target\": \"%s\"}", TopologyNode.Status.UNKNOWN, rkey));
 +                    }
 +
 +                    synchronized (runningResCheck) {
 +                        if (runningResCheck.contains(rkey)) {
 +                            LOG.debug("Running connection check for resource {}", rkey);
 +                        } else {
 +                            runningResCheck.add(rkey);
 +                        }
 +                    }
 +
 +                    executorService.execute(new ResCheck(rkey));
 +
 +                    break;
 +                case ADD_ENDPOINT:
 +                    handler.appendJavaScript(String.format("addEndpoint('%s', '%s', '%s');",
 +                            obj.get("source").asText(),
 +                            obj.get("target").asText(),
 +                            obj.get("scope").asText()));
 +                    break;
 +                default:
 +            }
 +
 +            executorService.shutdown();
 +
 +        } catch (IOException e) {
 +            LOG.error("Eror managing websocket message", e);
 +        }
 +    }
 +
 +    class ConnCheck implements Runnable {
 +
 +        private final Long key;
 +
 +        private final Application application;
 +
 +        private final Session session;
 +
-         public ConnCheck(final Long key) {
++        ConnCheck(final Long key) {
 +            this.key = key;
 +            this.application = Application.get();
 +            this.session = Session.exists() ? Session.get() : null;
 +        }
 +
 +        @Override
 +        public void run() {
 +            try {
 +                ThreadContext.setApplication(application);
 +                ThreadContext.setSession(session);
 +
 +                String res;
 +                try {
 +                    final ConnInstanceTO connector = connectorRestClient.read(key);
 +                    res = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}",
 +                            connectorRestClient.check(connector)
 +                                    ? TopologyNode.Status.REACHABLE : TopologyNode.Status.UNREACHABLE, key);
 +                } catch (Exception e) {
 +                    LOG.warn("Error checking connection for {}", key, e);
 +                    res = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", TopologyNode.Status.FAILURE, key);
 +                }
 +
 +                synchronized (runningConnCheck) {
 +                    connectors.put(key, res);
 +                    runningConnCheck.remove(key);
 +                }
 +            } finally {
 +                ThreadContext.detach();
 +            }
 +        }
 +    }
 +
 +    class ResCheck implements Runnable {
 +
 +        private final String key;
 +
 +        private final Application application;
 +
 +        private final Session session;
 +
-         public ResCheck(final String key) {
++        ResCheck(final String key) {
 +            this.key = key;
 +            this.application = Application.get();
 +            this.session = Session.exists() ? Session.get() : null;
 +        }
 +
 +        @Override
 +        public void run() {
 +            try {
 +                ThreadContext.setApplication(application);
 +                ThreadContext.setSession(session);
 +
 +                String res;
 +                try {
 +                    final ResourceTO resource = resourceRestClient.read(key);
 +                    res = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}",
 +                            connectorRestClient.check(resource)
 +                                    ? TopologyNode.Status.REACHABLE : TopologyNode.Status.UNREACHABLE, key);
 +                } catch (Exception e) {
 +                    LOG.warn("Error checking connection for {}", key, e);
 +                    res = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", TopologyNode.Status.FAILURE, key);
 +                }
 +
 +                synchronized (runningResCheck) {
 +                    resources.put(key, res);
 +                    runningResCheck.remove(key);
 +                }
 +            } finally {
 +                ThreadContext.detach();
 +            }
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
index ec405a2,0000000..1c6731f
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
@@@ -1,102 -1,0 +1,102 @@@
 +/*
 + * 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.console.wicket.markup.html.form;
 +
 +import java.io.Serializable;
 +import org.apache.wicket.ajax.AjaxRequestTarget;
 +
 +public abstract class ActionLink<T> implements Serializable {
 +
 +    private static final long serialVersionUID = 7031329706998320639L;
 +
 +    private boolean reloadFeedbackPanel = true;
 +
 +    private T modelObject;
 +
 +    public ActionLink() {
 +    }
 +
 +    public ActionLink(final T modelObject) {
 +        this.modelObject = modelObject;
 +    }
 +
 +    public enum ActionType {
 +
 +        MAPPING("update"),
 +        ACCOUNT_LINK("update"),
 +        RESET_TIME("update"),
 +        CLONE("create"),
 +        CREATE("create"),
 +        EDIT("read"),
 +        USER_TEMPLATE("read"),
 +        GROUP_TEMPLATE("read"),
 +        RESET("update"),
 +        ENABLE("update"),
 +        SEARCH("read"),
 +        DELETE("delete"),
 +        EXECUTE("execute"),
 +        DRYRUN("execute"),
 +        CLAIM("claim"),
 +        SELECT("read"),
 +        EXPORT("read"),
 +        SUSPEND("update"),
 +        REACTIVATE("update"),
 +        RELOAD("reload"),
 +        CHANGE_VIEW("changeView"),
 +        UNLINK("update"),
 +        LINK("update"),
 +        UNASSIGN("update"),
 +        ASSIGN("update"),
 +        DEPROVISION("update"),
 +        PROVISION("update"),
 +        MANAGE_RESOURCES("update"),
 +        MANAGE_USERS("update"),
 +        MANAGE_GROUPS("update"),
 +        ZOOM_IN("zoomin"),
 +        ZOOM_OUT("zoomout");
 +
 +        private final String actionId;
 +
-         private ActionType(final String actionId) {
++        ActionType(final String actionId) {
 +            this.actionId = actionId;
 +        }
 +
 +        public String getActionId() {
 +            return actionId;
 +        }
 +    }
 +
 +    public T getModelObject() {
 +        return modelObject;
 +    }
 +
 +    public abstract void onClick(final AjaxRequestTarget target, final T modelObject);
 +
 +    public void postClick() {
 +    }
 +
 +    public boolean feedbackPanelAutomaticReload() {
 +        return reloadFeedbackPanel;
 +    }
 +
 +    public ActionLink<T> feedbackPanelAutomaticReload(final boolean reloadFeedbackPanel) {
 +        this.reloadFeedbackPanel = reloadFeedbackPanel;
 +        return this;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/wizards/provision/ProvisionWizardBuilder.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/wizards/provision/ProvisionWizardBuilder.java
index 30a7bbc,0000000..161df03
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/provision/ProvisionWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/provision/ProvisionWizardBuilder.java
@@@ -1,222 -1,0 +1,222 @@@
 +/*
 + * Copyright 2015 The Apache Software Foundation.
 + *
 + * Licensed 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.console.wizards.provision;
 +
 +import java.io.Serializable;
 +import java.util.ArrayList;
 +import java.util.List;
 +import org.apache.commons.collections4.CollectionUtils;
 +import org.apache.commons.collections4.Predicate;
 +import org.apache.commons.collections4.Transformer;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.console.commons.Constants;
 +import org.apache.syncope.client.console.panels.ResourceMappingPanel;
 +import org.apache.syncope.client.console.rest.AnyTypeRestClient;
 +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
 +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
 +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 +import org.apache.syncope.client.console.wizards.AjaxWizardBuilder;
 +import org.apache.syncope.common.lib.to.AnyTypeTO;
 +import org.apache.syncope.common.lib.to.ProvisionTO;
 +import org.apache.syncope.common.lib.to.ResourceTO;
 +import org.apache.wicket.PageReference;
 +import org.apache.wicket.ajax.AjaxRequestTarget;
 +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 +import org.apache.wicket.extensions.wizard.WizardModel;
 +import org.apache.wicket.extensions.wizard.WizardStep;
 +import org.apache.wicket.markup.html.WebMarkupContainer;
 +import org.apache.wicket.markup.html.form.TextField;
 +import org.apache.wicket.model.LoadableDetachableModel;
 +import org.apache.wicket.model.Model;
 +import org.apache.wicket.model.PropertyModel;
 +import org.apache.wicket.model.ResourceModel;
 +import org.apache.wicket.model.StringResourceModel;
 +
 +public class ProvisionWizardBuilder extends AjaxWizardBuilder<ProvisionTO> implements Serializable {
 +
 +    private static final long serialVersionUID = 1L;
 +
 +    private final ResourceTO resourceTO;
 +
 +    private final LoadableDetachableModel<List<String>> anyTypes = new LoadableDetachableModel<List<String>>() {
 +
 +        private static final long serialVersionUID = 1L;
 +
 +        @Override
 +        protected List<String> load() {
 +            final List<String> currentlyAdded = new ArrayList<>();
 +
 +            CollectionUtils.collect(resourceTO.getProvisions(), new Transformer<ProvisionTO, String>() {
 +
 +                @Override
 +                public String transform(final ProvisionTO provisionTO) {
 +                    return provisionTO.getAnyType();
 +                }
 +            }, currentlyAdded);
 +
 +            final List<String> res = new ArrayList<>();
 +
 +            CollectionUtils.filter(
 +                    CollectionUtils.collect(new AnyTypeRestClient().getAll(), new Transformer<AnyTypeTO, String>() {
 +
 +                        @Override
 +                        public String transform(final AnyTypeTO anyTypeTO) {
 +                            return anyTypeTO.getKey();
 +                        }
 +                    }, res), new Predicate<String>() {
 +
 +                        @Override
 +                        public boolean evaluate(final String key) {
 +                            return !currentlyAdded.contains(key);
 +                        }
 +                    });
 +
 +            return res;
 +        }
 +    };
 +
 +    /**
 +     * The object type specification step.
 +     */
 +    private final class ObjectType extends WizardStep {
 +
 +        private static final long serialVersionUID = 1L;
 +
 +        /**
 +         * Construct.
 +         */
-         public ObjectType(final ProvisionTO item) {
++        ObjectType(final ProvisionTO item) {
 +            super(new ResourceModel("type.title", StringUtils.EMPTY),
 +                    new ResourceModel("type.summary", StringUtils.EMPTY), new Model<ProvisionTO>(item));
 +
 +            add(new AjaxDropDownChoicePanel<String>("type", "type", new PropertyModel<String>(item, "anyType"), false).
 +                    setChoices(anyTypes).
 +                    setStyleSheet("form-control").
 +                    setRequired(true));
 +
 +            add(new TextField<String>(
 +                    "class", new PropertyModel<String>(item, "objectClass")).setRequired(true));
 +        }
 +    }
 +
 +    /**
 +     * Mapping definition step.
 +     */
 +    private final class Mapping extends WizardStep {
 +
 +        private static final long serialVersionUID = 1L;
 +
 +        /**
 +         * Construct.
 +         */
-         public Mapping(final ProvisionTO item) {
++        Mapping(final ProvisionTO item) {
 +            setTitleModel(new ResourceModel("mapping.title", "Mapping"));
 +            setSummaryModel(new StringResourceModel("mapping.summary", this, new Model<ProvisionTO>(item)));
 +
 +            add(new ResourceMappingPanel("mapping", resourceTO, item));
 +        }
 +    }
 +
 +    /**
 +     * AccountLink specification step.
 +     */
 +    private final class ConnObjectLink extends WizardStep {
 +
 +        private static final long serialVersionUID = 1L;
 +
 +        /**
 +         * Construct.
 +         */
-         public ConnObjectLink(final ProvisionTO item) {
++        ConnObjectLink(final ProvisionTO item) {
 +            super(new ResourceModel("link.title", StringUtils.EMPTY),
 +                    new ResourceModel("link.summary", StringUtils.EMPTY));
 +
 +            final WebMarkupContainer connObjectLinkContainer = new WebMarkupContainer("connObjectLinkContainer");
 +            connObjectLinkContainer.setOutputMarkupId(true);
 +            add(connObjectLinkContainer);
 +
 +            boolean connObjectLinkEnabled = false;
 +            if (StringUtils.isNotBlank(item.getMapping().getConnObjectLink())) {
 +                connObjectLinkEnabled = true;
 +            }
 +
 +            final AjaxCheckBoxPanel connObjectLinkCheckbox = new AjaxCheckBoxPanel(
 +                    "connObjectLinkCheckbox",
 +                    new ResourceModel("connObjectLinkCheckbox", "connObjectLinkCheckbox").getObject(),
 +                    new Model<>(connObjectLinkEnabled),
 +                    false);
 +            connObjectLinkCheckbox.setEnabled(true);
 +
 +            connObjectLinkContainer.add(connObjectLinkCheckbox);
 +
 +            final AjaxTextFieldPanel connObjectLink = new AjaxTextFieldPanel(
 +                    "connObjectLink",
 +                    new ResourceModel("connObjectLink", "connObjectLink").getObject(),
 +                    new PropertyModel<String>(item.getMapping(), "connObjectLink"),
 +                    false);
 +            connObjectLink.setEnabled(connObjectLinkEnabled);
 +            connObjectLinkContainer.add(connObjectLink);
 +
 +            connObjectLinkCheckbox.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
 +
 +                private static final long serialVersionUID = -1107858522700306810L;
 +
 +                @Override
 +                protected void onUpdate(final AjaxRequestTarget target) {
 +                    if (connObjectLinkCheckbox.getModelObject()) {
 +                        connObjectLink.setEnabled(Boolean.TRUE);
 +                        connObjectLink.setModelObject("");
 +                    } else {
 +                        connObjectLink.setEnabled(Boolean.FALSE);
 +                        connObjectLink.setModelObject("");
 +                    }
 +
 +                    target.add(connObjectLink);
 +                }
 +            });
 +        }
 +    }
 +
 +    /**
 +     * Construct.
 +     *
 +     * @param id The component id
 +     * @param resourceTO external resource to be updated.
 +     * @param pageRef Caller page reference.
 +     */
 +    public ProvisionWizardBuilder(final String id, final ResourceTO resourceTO, final PageReference pageRef) {
 +        super(id, new ProvisionTO(), pageRef);
 +        this.resourceTO = resourceTO;
 +    }
 +
 +    @Override
 +    protected WizardModel buildModelSteps(final ProvisionTO modelObject, final WizardModel wizardModel) {
 +        wizardModel.add(new ObjectType(modelObject));
 +        wizardModel.add(new Mapping(modelObject));
 +        wizardModel.add(new ConnObjectLink(modelObject));
 +        return wizardModel;
 +    }
 +
 +    @Override
 +    protected void onCancelInternal() {
 +        // d nothing
 +    }
 +
 +    @Override
 +    protected void onApplyInternal() {
 +        // do nothing
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java
----------------------------------------------------------------------
diff --cc client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java
index 46dc302,0000000..724da5a
mode 100644,000000..100644
--- a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java
+++ b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java
@@@ -1,254 -1,0 +1,254 @@@
 +/*
 + * 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 com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +import javax.ws.rs.core.MediaType;
 +import javax.xml.bind.Marshaller;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.cxf.feature.Feature;
 +import org.apache.cxf.feature.LoggingFeature;
 +import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
 +import org.apache.cxf.staxutils.DocumentDepthProperties;
 +import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
 +import org.apache.syncope.common.rest.api.RESTHeaders;
 +
 +/**
 + * Factory bean for creating instances of {@link SyncopeClient}.
 + * Supports Spring-bean configuration and override via subclassing (see protected methods).
 + */
 +public class SyncopeClientFactoryBean {
 +
 +    public enum ContentType {
 +
 +        JSON(MediaType.APPLICATION_JSON_TYPE),
 +        XML(MediaType.APPLICATION_XML_TYPE);
 +
 +        private final MediaType mediaType;
 +
-         private ContentType(final MediaType mediaType) {
++        ContentType(final MediaType mediaType) {
 +            this.mediaType = mediaType;
 +        }
 +
 +        public MediaType getMediaType() {
 +            return mediaType;
 +        }
 +
 +        public static ContentType fromString(final String value) {
 +            return StringUtils.isNotBlank(value) && value.equalsIgnoreCase(XML.getMediaType().toString())
 +                    ? XML
 +                    : JSON;
 +        }
 +    }
 +
 +    private JacksonJaxbJsonProvider jsonProvider;
 +
 +    private JAXBElementProvider<?> jaxbProvider;
 +
 +    private RestClientExceptionMapper exceptionMapper;
 +
 +    private String address;
 +
 +    private ContentType contentType;
 +
 +    private String domain;
 +
 +    private boolean useCompression;
 +
 +    private RestClientFactoryBean restClientFactoryBean;
 +
 +    protected JacksonJaxbJsonProvider defaultJsonProvider() {
 +        return new JacksonJaxbJsonProvider();
 +    }
 +
 +    @SuppressWarnings({ "rawtypes" })
 +    protected JAXBElementProvider<?> defaultJAXBProvider() {
 +        JAXBElementProvider<?> defaultJAXBProvider = new JAXBElementProvider();
 +
 +        DocumentDepthProperties depthProperties = new DocumentDepthProperties();
 +        depthProperties.setInnerElementCountThreshold(500);
 +        defaultJAXBProvider.setDepthProperties(depthProperties);
 +
 +        Map<String, Object> marshallerProperties = new HashMap<>();
 +        marshallerProperties.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
 +        defaultJAXBProvider.setMarshallerProperties(marshallerProperties);
 +
 +        Map<String, String> collectionWrapperMap = new HashMap<>();
 +        collectionWrapperMap.put(AbstractPolicyTO.class.getName(), "policies");
 +        defaultJAXBProvider.setCollectionWrapperMap(collectionWrapperMap);
 +
 +        return defaultJAXBProvider;
 +    }
 +
 +    protected RestClientExceptionMapper defaultExceptionMapper() {
 +        return new RestClientExceptionMapper();
 +    }
 +
 +    protected RestClientFactoryBean defaultRestClientFactoryBean() {
 +        RestClientFactoryBean defaultRestClientFactoryBean = new RestClientFactoryBean();
 +
 +        if (StringUtils.isBlank(address)) {
 +            throw new IllegalArgumentException("Property 'address' is missing");
 +        }
 +        defaultRestClientFactoryBean.setAddress(address);
 +
 +        if (StringUtils.isNotBlank(domain)) {
 +            defaultRestClientFactoryBean.setHeaders(Collections.singletonMap(RESTHeaders.DOMAIN, domain));
 +        }
 +
 +        defaultRestClientFactoryBean.setThreadSafe(true);
 +        defaultRestClientFactoryBean.setInheritHeaders(true);
 +
 +        List<Feature> features = new ArrayList<>();
 +        features.add(new LoggingFeature());
 +        defaultRestClientFactoryBean.setFeatures(features);
 +
 +        List<Object> providers = new ArrayList<>(3);
 +        providers.add(getJaxbProvider());
 +        providers.add(getJsonProvider());
 +        providers.add(getExceptionMapper());
 +        defaultRestClientFactoryBean.setProviders(providers);
 +
 +        return defaultRestClientFactoryBean;
 +    }
 +
 +    public JacksonJaxbJsonProvider getJsonProvider() {
 +        return jsonProvider == null
 +                ? defaultJsonProvider()
 +                : jsonProvider;
 +    }
 +
 +    public void setJsonProvider(final JacksonJaxbJsonProvider jsonProvider) {
 +        this.jsonProvider = jsonProvider;
 +    }
 +
 +    public JAXBElementProvider<?> getJaxbProvider() {
 +        return jaxbProvider == null
 +                ? defaultJAXBProvider()
 +                : jaxbProvider;
 +    }
 +
 +    public SyncopeClientFactoryBean setJaxbProvider(final JAXBElementProvider<?> jaxbProvider) {
 +        this.jaxbProvider = jaxbProvider;
 +        return this;
 +    }
 +
 +    public RestClientExceptionMapper getExceptionMapper() {
 +        return exceptionMapper == null
 +                ? defaultExceptionMapper()
 +                : exceptionMapper;
 +    }
 +
 +    public SyncopeClientFactoryBean setExceptionMapper(final RestClientExceptionMapper exceptionMapper) {
 +        this.exceptionMapper = exceptionMapper;
 +        return this;
 +    }
 +
 +    public String getAddress() {
 +        return address;
 +    }
 +
 +    public SyncopeClientFactoryBean setAddress(final String address) {
 +        this.address = address;
 +        return this;
 +    }
 +
 +    public ContentType getContentType() {
 +        return contentType == null
 +                ? ContentType.JSON
 +                : contentType;
 +    }
 +
 +    public SyncopeClientFactoryBean setContentType(final ContentType contentType) {
 +        this.contentType = contentType;
 +        return this;
 +    }
 +
 +    public SyncopeClientFactoryBean setContentType(final String contentType) {
 +        this.contentType = ContentType.fromString(contentType);
 +        return this;
 +    }
 +
 +    public String getDomain() {
 +        return domain;
 +    }
 +
 +    public SyncopeClientFactoryBean setDomain(final String domain) {
 +        this.domain = domain;
 +        return this;
 +    }
 +
 +    /**
 +     * Sets the given service instance for transparent gzip <tt>Content-Encoding</tt> handling.
 +     *
 +     * @param useCompression whether transparent gzip <tt>Content-Encoding</tt> handling is to be enabled
 +     * @return the current instance
 +     */
 +    public SyncopeClientFactoryBean setUseCompression(final boolean useCompression) {
 +        this.useCompression = useCompression;
 +        return this;
 +    }
 +
 +    public boolean isUseCompression() {
 +        return useCompression;
 +    }
 +
 +    public RestClientFactoryBean getRestClientFactoryBean() {
 +        return restClientFactoryBean == null
 +                ? defaultRestClientFactoryBean()
 +                : restClientFactoryBean;
 +    }
 +
 +    public SyncopeClientFactoryBean setRestClientFactoryBean(final RestClientFactoryBean restClientFactoryBean) {
 +        this.restClientFactoryBean = restClientFactoryBean;
 +        return this;
 +    }
 +
 +    /**
 +     * Builds client instance with no authentication, for user self-registration and related queries (schema,
 +     * resources, ...).
 +     *
 +     * @return client instance with no authentication
 +     */
 +    public SyncopeClient create() {
 +        return create(null, null);
 +    }
 +
 +    /**
 +     * Builds client instance with the given credentials.
 +     *
 +     * @param username username
 +     * @param password password
 +     * @return client instance with the given credentials
 +     */
 +    public SyncopeClient create(final String username, final String password) {
 +        return new SyncopeClient(
 +                getContentType().getMediaType(),
 +                getRestClientFactoryBean(),
 +                getExceptionMapper(),
 +                username,
 +                password,
 +                useCompression);
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java
index ee35e28,0000000..136d798
mode 100644,000000..100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java
@@@ -1,44 -1,0 +1,44 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *   http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.syncope.common.lib.types;
 +
 +import javax.xml.bind.annotation.XmlEnum;
 +import org.apache.syncope.common.lib.to.AnyObjectTO;
 +import org.apache.syncope.common.lib.to.AnyTO;
 +import org.apache.syncope.common.lib.to.GroupTO;
 +import org.apache.syncope.common.lib.to.UserTO;
 +
 +@XmlEnum
 +public enum AnyTypeKind {
 +
 +    USER(UserTO.class),
 +    GROUP(GroupTO.class),
 +    ANY_OBJECT(AnyObjectTO.class);
 +
 +    private final Class<? extends AnyTO> toClass;
 +
-     private AnyTypeKind(final Class<? extends AnyTO> toClass) {
++    AnyTypeKind(final Class<? extends AnyTO> toClass) {
 +        this.toClass = toClass;
 +    }
 +
 +    public Class<? extends AnyTO> getToClass() {
 +        return toClass;
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
index 0c19403,0000000..e4a0f10
mode 100644,000000..100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
@@@ -1,103 -1,0 +1,103 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *   http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.syncope.common.lib.types;
 +
 +import javax.ws.rs.core.Response;
 +
 +public enum ClientExceptionType {
 +
 +    AssociatedResources(Response.Status.BAD_REQUEST),
 +    Composite(Response.Status.BAD_REQUEST),
 +    ConcurrentModification(Response.Status.PRECONDITION_FAILED),
 +    ConnectorException(Response.Status.BAD_REQUEST),
 +    DataIntegrityViolation(Response.Status.CONFLICT),
 +    EntityExists(Response.Status.CONFLICT),
 +    GenericPersistence(Response.Status.BAD_REQUEST),
 +    InvalidSecurityAnswer(Response.Status.BAD_REQUEST),
 +    InvalidEntity(Response.Status.BAD_REQUEST),
 +    InvalidLogger(Response.Status.BAD_REQUEST),
 +    InvalidConnInstance(Response.Status.BAD_REQUEST),
 +    InvalidConnIdConf(Response.Status.BAD_REQUEST),
 +    InvalidPolicy(Response.Status.BAD_REQUEST),
 +    InvalidConf(Response.Status.BAD_REQUEST),
 +    InvalidPath(Response.Status.BAD_REQUEST),
 +    InvalidProvision(Response.Status.BAD_REQUEST),
 +    InvalidReport(Response.Status.BAD_REQUEST),
 +    InvalidReportExec(Response.Status.BAD_REQUEST),
 +    InvalidRelationshipType(Response.Status.BAD_REQUEST),
 +    InvalidAnyType(Response.Status.BAD_REQUEST),
 +    InvalidAnyObject(Response.Status.BAD_REQUEST),
 +    InvalidGroup(Response.Status.BAD_REQUEST),
 +    InvalidSchemaDefinition(Response.Status.BAD_REQUEST),
 +    InvalidSearchExpression(Response.Status.BAD_REQUEST),
 +    InvalidPageOrSize(Response.Status.BAD_REQUEST),
 +    InvalidPropagationTaskExecReport(Response.Status.BAD_REQUEST),
 +    InvalidPlainSchema(Response.Status.BAD_REQUEST),
 +    InvalidDerSchema(Response.Status.BAD_REQUEST),
 +    InvalidVirSchema(Response.Status.BAD_REQUEST),
 +    InvalidMapping(Response.Status.BAD_REQUEST),
 +    InvalidRealm(Response.Status.BAD_REQUEST),
 +    InvalidUser(Response.Status.BAD_REQUEST),
 +    InvalidExternalResource(Response.Status.BAD_REQUEST),
 +    InvalidNotification(Response.Status.BAD_REQUEST),
 +    InvalidPropagationTask(Response.Status.BAD_REQUEST),
 +    InvalidSchedTask(Response.Status.BAD_REQUEST),
 +    InvalidSyncTask(Response.Status.BAD_REQUEST),
 +    InvalidValues(Response.Status.BAD_REQUEST),
 +    NotFound(Response.Status.NOT_FOUND),
 +    RejectedUserCreate(Response.Status.BAD_REQUEST),
 +    RequiredValuesMissing(Response.Status.BAD_REQUEST),
 +    RESTValidation(Response.Status.BAD_REQUEST),
 +    GroupOwnership(Response.Status.BAD_REQUEST),
 +    Scheduling(Response.Status.BAD_REQUEST),
 +    DelegatedAdministration(Response.Status.FORBIDDEN),
 +    UnallowedSchemas(Response.Status.BAD_REQUEST),
 +    Unknown(Response.Status.BAD_REQUEST),
 +    Workflow(Response.Status.BAD_REQUEST);
 +
 +    private final Response.Status responseStatus;
 +
-     private ClientExceptionType(final Response.Status responseStatus) {
++    ClientExceptionType(final Response.Status responseStatus) {
 +        this.responseStatus = responseStatus;
 +    }
 +
 +    public static ClientExceptionType fromHeaderValue(final String exceptionTypeHeaderValue) {
 +        ClientExceptionType result = null;
 +        for (ClientExceptionType type : values()) {
 +            if (exceptionTypeHeaderValue.equals(type.name())) {
 +                result = type;
 +            }
 +        }
 +
 +        if (result == null) {
 +            throw new IllegalArgumentException("Unexpected header value: " + exceptionTypeHeaderValue);
 +        }
 +
 +        return result;
 +    }
 +
 +    public String getInfoHeaderValue(final String value) {
 +        return name() + ":" + value;
 +    }
 +
 +    public Response.Status getResponseStatus() {
 +        return responseStatus;
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
index 4588a36,0000000..eccb89d
mode 100644,000000..100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
@@@ -1,201 -1,0 +1,201 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *   http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.syncope.common.lib.types;
 +
 +import java.util.Collection;
 +import java.util.EnumSet;
 +import java.util.HashSet;
 +import java.util.Set;
 +
 +import javax.xml.bind.annotation.XmlEnum;
 +
 +/**
 + * Internal attribute mapping type.
 + */
 +@XmlEnum
 +public enum IntMappingType {
 +
 +    // Unfortunately enum type cannot be extended ...
 +    // -------------------------
 +    // User attribute types (the same in UserMappingType)
 +    // -------------------------
 +    UserPlainSchema(AnyTypeKind.USER),
 +    UserDerivedSchema(AnyTypeKind.USER),
 +    UserVirtualSchema(AnyTypeKind.USER),
 +    UserKey(AnyTypeKind.USER),
 +    Username(AnyTypeKind.USER),
 +    Password(AnyTypeKind.USER),
 +    // -------------------------
 +    // Group attribute types (the same in GroupMappingType)
 +    // -------------------------
 +    GroupPlainSchema(AnyTypeKind.GROUP),
 +    GroupDerivedSchema(AnyTypeKind.GROUP),
 +    GroupVirtualSchema(AnyTypeKind.GROUP),
 +    GroupKey(AnyTypeKind.GROUP),
 +    GroupName(AnyTypeKind.GROUP),
 +    GroupOwnerSchema(AnyTypeKind.GROUP),
 +    // -------------------------
 +    // Any attribute types (the same in AnyMappingType)
 +    // -------------------------
 +    AnyObjectPlainSchema(AnyTypeKind.ANY_OBJECT),
 +    AnyObjectDerivedSchema(AnyTypeKind.ANY_OBJECT),
 +    AnyObjectVirtualSchema(AnyTypeKind.ANY_OBJECT),
 +    AnyObjectKey(AnyTypeKind.ANY_OBJECT);
 +
 +    private final AnyTypeKind anyTypeKind;
 +
-     private IntMappingType(final AnyTypeKind anyTypeKind) {
++    IntMappingType(final AnyTypeKind anyTypeKind) {
 +        this.anyTypeKind = anyTypeKind;
 +    }
 +
 +    public AnyTypeKind getAnyTypeKind() {
 +        return anyTypeKind;
 +    }
 +
 +    /**
 +     * Get attribute types for a certain any object type.
 +     *
 +     * @param anyTypeKind any object type
 +     * @param toBeFiltered types to be filtered from the result.
 +     * @return set of attribute types.
 +     */
 +    public static Set<IntMappingType> getAttributeTypes(
 +            final AnyTypeKind anyTypeKind, final Collection<IntMappingType> toBeFiltered) {
 +
 +        final Set<IntMappingType> res = getAttributeTypes(anyTypeKind);
 +        res.removeAll(toBeFiltered);
 +
 +        return res;
 +    }
 +
 +    /**
 +     * Get attribute types for a certain any object type.
 +     *
 +     * @param anyTypeKind any object type
 +     * @return set of attribute types.
 +     */
 +    public static Set<IntMappingType> getAttributeTypes(final AnyTypeKind anyTypeKind) {
 +        EnumSet<?> enumset;
 +
 +        switch (anyTypeKind) {
 +            case GROUP:
 +                enumset = EnumSet.allOf(GroupMappingType.class);
 +                break;
 +
 +            case ANY_OBJECT:
 +                enumset = EnumSet.allOf(AnyMappingType.class);
 +                break;
 +
 +            case USER:
 +            default:
 +                enumset = EnumSet.allOf(UserMappingType.class);
 +                break;
 +        }
 +
 +        final Set<IntMappingType> result = new HashSet<>(enumset.size());
 +        for (Object obj : enumset) {
 +            result.add(IntMappingType.valueOf(obj.toString()));
 +        }
 +
 +        return result;
 +    }
 +
 +    public static Set<IntMappingType> getEmbedded() {
 +        return EnumSet.of(IntMappingType.UserKey, IntMappingType.Username, IntMappingType.Password,
 +                IntMappingType.GroupKey, IntMappingType.GroupName, IntMappingType.GroupOwnerSchema,
 +                IntMappingType.AnyObjectKey);
 +    }
 +
 +    /**
 +     * Check if attribute type belongs to the specified any object type set.
 +     *
 +     * @param anyTypeKind any object type.
 +     * @param type attribute type.
 +     * @return true if attribute type belongs to the specified any object type set.
 +     */
 +    public static boolean contains(final AnyTypeKind anyTypeKind, final String type) {
 +        switch (anyTypeKind) {
 +            case GROUP:
 +                for (GroupMappingType c : GroupMappingType.values()) {
 +                    if (c.name().equals(type)) {
 +                        return true;
 +                    }
 +                }
 +                break;
 +
 +            case ANY_OBJECT:
 +                for (AnyMappingType c : AnyMappingType.values()) {
 +                    if (c.name().equals(type)) {
 +                        return true;
 +                    }
 +                }
 +                break;
 +
 +            case USER:
 +            default:
 +                for (UserMappingType c : UserMappingType.values()) {
 +                    if (c.name().equals(type)) {
 +                        return true;
 +                    }
 +                }
 +                break;
 +        }
 +        return false;
 +    }
 +
 +    /**
 +     * User attribute types.
 +     */
 +    private enum UserMappingType {
 +
 +        UserPlainSchema,
 +        UserDerivedSchema,
 +        UserVirtualSchema,
 +        UserKey,
 +        Username,
 +        Password;
 +
 +    }
 +
 +    /**
 +     * Group attribute types.
 +     */
 +    private enum GroupMappingType {
 +
 +        GroupPlainSchema,
 +        GroupDerivedSchema,
 +        GroupVirtualSchema,
 +        GroupKey,
 +        GroupName,
 +        GroupOwnerSchema;
 +
 +    }
 +
 +    /**
 +     * Any attribute types.
 +     */
 +    private enum AnyMappingType {
 +
 +        AnyObjectPlainSchema,
 +        AnyObjectDerivedSchema,
 +        AnyObjectVirtualSchema,
 +        AnyObjectKey;
 +
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java
index a60a5af,0000000..ce1b5cd
mode 100644,000000..100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java
@@@ -1,54 -1,0 +1,54 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *   http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.syncope.common.lib.types;
 +
 +import javax.xml.bind.annotation.XmlEnum;
 +
 +@XmlEnum
 +public enum TaskType {
 +
 +    PROPAGATION("propagation"),
 +    NOTIFICATION("notification"),
 +    SCHEDULED("sched"),
 +    SYNCHRONIZATION("sync"),
 +    PUSH("push");
 +
 +    private final String name;
 +
-     private TaskType(final String name) {
++    TaskType(final String name) {
 +        this.name = name;
 +    }
 +
 +    @Override
 +    public String toString() {
 +        return name;
 +    }
 +
 +    public static TaskType fromString(final String name) {
 +        if (name != null) {
 +            for (TaskType t : TaskType.values()) {
 +                if (t.name.equalsIgnoreCase(name)) {
 +                    return t;
 +                }
 +            }
 +        }
 +
 +        return null;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/Preference.java
----------------------------------------------------------------------
diff --cc common/rest-api/src/main/java/org/apache/syncope/common/rest/api/Preference.java
index a448c03,0000000..8d21e54
mode 100644,000000..100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/Preference.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/Preference.java
@@@ -1,59 -1,0 +1,59 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *   http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.syncope.common.rest.api;
 +
 +/**
 + * Preferences available to be specified during requests.
 + *
 + * @see RESTHeaders#PREFER
 + * @see RESTHeaders#PREFERENCE_APPLIED
 + */
 +public enum Preference {
 +
 +    NONE(""),
 +    RETURN_CONTENT("return-content"),
 +    RETURN_NO_CONTENT("return-no-content");
 +
 +    private final String literal;
 +
-     private Preference(final String literal) {
++    Preference(final String literal) {
 +        this.literal = literal;
 +    }
 +
 +    @Override
 +    public String toString() {
 +        return literal;
 +    }
 +
 +    public static Preference fromString(final String literal) {
 +        Preference result = null;
 +
 +        for (Preference preference : values()) {
 +            if (preference.toString().equalsIgnoreCase(literal)) {
 +                result = preference;
 +            }
 +        }
 +
 +        if (result == null) {
 +            result = NONE;
 +        }
 +
 +        return result;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
----------------------------------------------------------------------
diff --cc core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
index e85058c,0000000..9a796ef
mode 100644,000000..100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
@@@ -1,259 -1,0 +1,259 @@@
 +/*
 + * 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.logic;
 +
 +import java.util.ArrayList;
 +import java.util.Collection;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Set;
 +import org.apache.commons.collections4.CollectionUtils;
 +import org.apache.commons.collections4.Predicate;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.patch.AnyPatch;
 +import org.apache.syncope.common.lib.to.AnyTO;
 +import org.apache.syncope.common.lib.to.GroupTO;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.ClientExceptionType;
 +import org.apache.syncope.core.misc.RealmUtils;
 +import org.apache.syncope.core.misc.TemplateUtils;
 +import org.apache.syncope.core.misc.security.DelegatedAdministrationException;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 +import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 +import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 +import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 +import org.apache.syncope.core.persistence.api.entity.AnyType;
 +import org.apache.syncope.core.persistence.api.entity.Realm;
 +import org.apache.syncope.core.provisioning.api.LogicActions;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.beans.factory.support.AbstractBeanDefinition;
 +
 +public abstract class AbstractAnyLogic<TO extends AnyTO, P extends AnyPatch>
 +        extends AbstractResourceAssociator<TO> {
 +
 +    @Autowired
 +    private RealmDAO realmDAO;
 +
 +    @Autowired
 +    private AnyTypeDAO anyTypeDAO;
 +
 +    @Autowired
 +    private TemplateUtils templateUtils;
 +
 +    private List<LogicActions> getActions(final Realm realm) {
 +        List<LogicActions> actions = new ArrayList<>();
 +
 +        for (String className : realm.getActionsClassNames()) {
 +            try {
 +                Class<?> actionsClass = Class.forName(className);
 +                LogicActions logicActions = (LogicActions) ApplicationContextProvider.getBeanFactory().
 +                        createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
 +
 +                actions.add(logicActions);
 +            } catch (Exception e) {
 +                LOG.warn("Class '{}' not found", className, e);
 +            }
 +        }
 +
 +        return actions;
 +    }
 +
 +    protected Pair<TO, List<LogicActions>> beforeCreate(final TO input) {
 +        Realm realm = realmDAO.find(input.getRealm());
 +        if (realm == null) {
 +            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
 +            sce.getElements().add(input.getRealm());
 +            throw sce;
 +        }
 +
 +        AnyType anyType = input instanceof UserTO
 +                ? anyTypeDAO.findUser()
 +                : input instanceof GroupTO
 +                        ? anyTypeDAO.findGroup()
 +                        : anyTypeDAO.find(input.getType());
 +        if (anyType == null) {
 +            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidAnyType);
 +            sce.getElements().add(input.getType());
 +            throw sce;
 +        }
 +
 +        TO any = input;
 +
 +        templateUtils.apply(any, realm.getTemplate(anyType));
 +
 +        List<LogicActions> actions = getActions(realm);
 +        for (LogicActions action : actions) {
 +            any = action.beforeCreate(any);
 +        }
 +
 +        LOG.debug("Input: {}\nOutput: {}\n", input, any);
 +
 +        return ImmutablePair.of(any, actions);
 +    }
 +
 +    protected TO afterCreate(final TO input, final List<LogicActions> actions) {
 +        TO any = input;
 +
 +        for (LogicActions action : actions) {
 +            any = action.afterCreate(any);
 +        }
 +
 +        return any;
 +    }
 +
 +    protected Pair<P, List<LogicActions>> beforeUpdate(final P input, final String realmPath) {
 +        Realm realm = realmDAO.find(realmPath);
 +        if (realm == null) {
 +            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
 +            sce.getElements().add(realmPath);
 +            throw sce;
 +        }
 +
 +        P mod = input;
 +
 +        List<LogicActions> actions = getActions(realm);
 +        for (LogicActions action : actions) {
 +            mod = action.beforeUpdate(mod);
 +        }
 +
 +        LOG.debug("Input: {}\nOutput: {}\n", input, mod);
 +
 +        return ImmutablePair.of(mod, actions);
 +    }
 +
 +    protected TO afterUpdate(final TO input, final List<LogicActions> actions) {
 +        TO any = input;
 +
 +        for (LogicActions action : actions) {
 +            any = action.afterUpdate(any);
 +        }
 +
 +        return any;
 +    }
 +
 +    protected Pair<TO, List<LogicActions>> beforeDelete(final TO input) {
 +        Realm realm = realmDAO.find(input.getRealm());
 +        if (realm == null) {
 +            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
 +            sce.getElements().add(input.getRealm());
 +            throw sce;
 +        }
 +
 +        TO any = input;
 +
 +        List<LogicActions> actions = getActions(realm);
 +        for (LogicActions action : actions) {
 +            any = action.beforeDelete(any);
 +        }
 +
 +        LOG.debug("Input: {}\nOutput: {}\n", input, any);
 +
 +        return ImmutablePair.of(any, actions);
 +    }
 +
 +    protected TO afterDelete(final TO input, final List<LogicActions> actions) {
 +        TO any = input;
 +
 +        for (LogicActions action : actions) {
 +            any = action.afterDelete(any);
 +        }
 +
 +        return any;
 +    }
 +
 +    private static class StartsWithPredicate implements Predicate<String> {
 +
 +        private final Collection<String> targets;
 +
-         public StartsWithPredicate(final Collection<String> targets) {
++        StartsWithPredicate(final Collection<String> targets) {
 +            this.targets = targets;
 +        }
 +
 +        @Override
 +        public boolean evaluate(final String realm) {
 +            return CollectionUtils.exists(targets, new Predicate<String>() {
 +
 +                @Override
 +                public boolean evaluate(final String target) {
 +                    return realm.startsWith(target);
 +                }
 +            });
 +        }
 +
 +    }
 +
 +    protected Set<String> getEffectiveRealms(
 +            final Set<String> allowedRealms, final Collection<String> requestedRealms) {
 +
 +        Set<String> allowed = RealmUtils.normalize(allowedRealms);
 +        Set<String> requested = RealmUtils.normalize(requestedRealms);
 +
 +        Set<String> effective = new HashSet<>();
 +        CollectionUtils.select(requested, new StartsWithPredicate(allowed), effective);
 +        CollectionUtils.select(allowed, new StartsWithPredicate(requested), effective);
 +
 +        return effective;
 +    }
 +
 +    protected void securityChecks(final Set<String> effectiveRealms, final String realm, final Long key) {
 +        if (!CollectionUtils.exists(effectiveRealms, new Predicate<String>() {
 +
 +            @Override
 +            public boolean evaluate(final String ownedRealm) {
 +                return realm.startsWith(ownedRealm);
 +            }
 +        })) {
 +
 +            throw new DelegatedAdministrationException(
 +                    this instanceof UserLogic
 +                            ? AnyTypeKind.USER
 +                            : this instanceof GroupLogic
 +                                    ? AnyTypeKind.GROUP
 +                                    : AnyTypeKind.ANY_OBJECT,
 +                    key);
 +        }
 +    }
 +
 +    public abstract TO read(Long key);
 +
 +    public abstract int count(List<String> realms);
 +
 +    public abstract TO create(TO anyTO);
 +
 +    public abstract TO update(P anyPatch);
 +
 +    public abstract TO delete(Long key);
 +
 +    public abstract List<TO> list(
 +            int page, int size, List<OrderByClause> orderBy,
 +            List<String> realms,
 +            boolean details);
 +
 +    public abstract List<TO> search(
 +            SearchCond searchCondition,
 +            int page, int size, List<OrderByClause> orderBy,
 +            List<String> realms,
 +            boolean details);
 +
 +    public abstract int searchCount(SearchCond searchCondition, List<String> realms);
 +}


[37/54] [abbrv] syncope git commit: refactoring of the schema and notification stack + bugfixing, SYNCOPE-158

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationDelete.java
new file mode 100644
index 0000000..1e4b96d
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationDelete.java
@@ -0,0 +1,56 @@
+/*
+ * 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.cli.commands.notification;
+
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.common.lib.SyncopeClientException;
+
+public class NotificationDelete extends AbstractNotificationCommand {
+
+    private static final String DELETE_HELP_MESSAGE = "notification --delete {NOTIFICATION-ID} {NOTIFICATION-ID} [...]";
+
+    private final Input input;
+
+    public NotificationDelete(final Input input) {
+        this.input = input;
+    }
+
+    public void delete() {
+        if (input.parameterNumber() >= 1) {
+            for (final String parameter : input.getParameters()) {
+                try {
+                    notificationService.delete(Long.valueOf(parameter));
+                    notificationResultManager.deletedMessage("Notification", parameter);
+                } catch (final WebServiceException | SyncopeClientException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        notificationResultManager.notFoundError("Notification", parameter);
+                    } else {
+                        Messages.printMessage(ex.getMessage());
+                    }
+                } catch (final NumberFormatException ex) {
+                    notificationResultManager.notBooleanDeletedError("notification", parameter);
+                }
+            }
+        } else {
+            notificationResultManager.commandOptionError(DELETE_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationList.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationList.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationList.java
new file mode 100644
index 0000000..ff9561c
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationList.java
@@ -0,0 +1,35 @@
+/*
+ * 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.cli.commands.notification;
+
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.NotificationTO;
+
+public class NotificationList extends AbstractNotificationCommand {
+
+    public void list() {
+        try {
+            for (final NotificationTO notificationTO : notificationService.list()) {
+                System.out.println(notificationTO);
+            }
+        } catch (final SyncopeClientException ex) {
+            notificationResultManager.generic(ex.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationRead.java
new file mode 100644
index 0000000..386700c
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationRead.java
@@ -0,0 +1,54 @@
+/*
+ * 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.cli.commands.notification;
+
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+
+public class NotificationRead extends AbstractNotificationCommand {
+
+    private static final String READ_HELP_MESSAGE = "notification --read {NOTIFICATION-ID} {NOTIFICATION-ID} [...]";
+
+    private final Input input;
+
+    public NotificationRead(final Input input) {
+        this.input = input;
+    }
+
+    public void read() {
+        if (input.parameterNumber() >= 1) {
+            for (final String parameter : input.getParameters()) {
+                try {
+                    System.out.println(notificationService.read(Long.valueOf(parameter)));
+                } catch (final NumberFormatException ex) {
+                    notificationResultManager.notBooleanDeletedError("notification", parameter);
+                } catch (final WebServiceException | SyncopeClientException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        notificationResultManager.notFoundError("Notification", parameter);
+                    } else {
+                        notificationResultManager.generic(ex.getMessage());
+                    }
+                }
+            }
+        } else {
+            notificationResultManager.commandOptionError(READ_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationResultManager.java
new file mode 100644
index 0000000..d16d88b
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/notification/NotificationResultManager.java
@@ -0,0 +1,25 @@
+/*
+ * 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.cli.commands.notification;
+
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+
+public class NotificationResultManager extends CommonsResultManager {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/AbstractSchemaCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/AbstractSchemaCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/AbstractSchemaCommand.java
new file mode 100644
index 0000000..3074135
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/AbstractSchemaCommand.java
@@ -0,0 +1,30 @@
+/*
+ * 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.cli.commands.schema;
+
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.common.rest.api.service.SchemaService;
+
+public abstract class AbstractSchemaCommand {
+
+    protected final SchemaService schemaService = SyncopeServices.get(SchemaService.class);
+    
+    protected final SchemaResultManager schemaResultManager = new SchemaResultManager();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaCommand.java
new file mode 100644
index 0000000..193c79b
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaCommand.java
@@ -0,0 +1,127 @@
+/*
+ * 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.cli.commands.schema;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.commands.AbstractCommand;
+
+@Command(name = "schema")
+public class SchemaCommand extends AbstractCommand {
+
+    private static final String HELP_MESSAGE = "Usage: schema [options]\n"
+            + "  Options:\n"
+            + "    --help \n"
+            + "    --list-all\n"
+            + "    --list-plain\n"
+            + "    --list-derived\n"
+            + "    --list-virtual\n"
+            + "    --read {SCHEMA-TYPE} {SCHEMA-KEY}\n"
+            + "        Schema type: PLAIN / DERIVED / VIRTUAL\n"
+            + "    --delete {SCHEMA-TYPE} {SCHEMA-KEY}\n"
+            + "        Schema type: PLAIN / DERIVED / VIRTUAL";
+
+    @Override
+    public void execute(final Input input) {
+        if (StringUtils.isBlank(input.getOption())) {
+            input.setOption(Options.HELP.getOptionName());
+        }
+
+        switch (Options.fromName(input.getOption())) {
+            case LIST:
+                new SchemaList(input).list();
+                break;
+            case LIST_ALL:
+                new SchemaListAll().listAll();
+                break;
+            case LIST_PLAIN:
+                new SchemaListPlain().listPlain();
+                break;
+            case LIST_DERIVED:
+                new SchemaListDerived().listDerived();
+                break;
+            case LIST_VIRTUAL:
+                new SchemaListVirtual().listVirtual();
+                break;
+            case READ:
+                new SchemaRead(input).read();
+                break;
+            case DELETE:
+                new SchemaDelete(input).delete();
+                break;
+            case HELP:
+                System.out.println(HELP_MESSAGE);
+                break;
+            default:
+                new SchemaResultManager().defaultError(input.getOption(), HELP_MESSAGE);
+        }
+    }
+
+    @Override
+    public String getHelpMessage() {
+        return HELP_MESSAGE;
+    }
+
+    private enum Options {
+
+        HELP("--help"),
+        LIST("--list"),
+        LIST_ALL("--list-all"),
+        LIST_PLAIN("--list-plain"),
+        LIST_DERIVED("--list-derived"),
+        LIST_VIRTUAL("--list-virtual"),
+        READ("--read"),
+        DELETE("--delete");
+
+        private final String optionName;
+
+        Options(final String optionName) {
+            this.optionName = optionName;
+        }
+
+        public String getOptionName() {
+            return optionName;
+        }
+
+        public boolean equalsOptionName(final String otherName) {
+            return (otherName == null) ? false : optionName.equals(otherName);
+        }
+
+        public static Options fromName(final String name) {
+            Options optionToReturn = HELP;
+            for (final Options option : Options.values()) {
+                if (option.equalsOptionName(name)) {
+                    optionToReturn = option;
+                }
+            }
+            return optionToReturn;
+        }
+
+        public static List<String> toList() {
+            final List<String> options = new ArrayList<>();
+            for (final Options value : values()) {
+                options.add(value.getOptionName());
+            }
+            return options;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaDelete.java
new file mode 100644
index 0000000..9cf6fe2
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaDelete.java
@@ -0,0 +1,64 @@
+/*
+ * 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.cli.commands.schema;
+
+import java.util.Arrays;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.util.CommandUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.types.SchemaType;
+
+public class SchemaDelete extends AbstractSchemaCommand {
+
+    private static final String DELETE_HELP_MESSAGE = "schema --delete {SCHEMA-TYPE} {SCHEMA-KEY}\n"
+            + "   Schema type: PLAIN / DERIVED / VIRTUAL";
+
+    private final Input input;
+
+    public SchemaDelete(final Input input) {
+        this.input = input;
+    }
+
+    public void delete() {
+        if (input.parameterNumber() >= 2) {
+            final String[] parameters = Arrays.copyOfRange(input.getParameters(), 1, input.parameterNumber());
+            try {
+                for (final String parameter : parameters) {
+                    schemaService.delete(SchemaType.valueOf(input.firstParameter()), parameter);
+                    schemaResultManager.deletedMessage("Schema", parameter);
+                }
+            } catch (final SyncopeClientException | WebServiceException ex) {
+                if (ex.getMessage().startsWith("NotFound")) {
+                    schemaResultManager.notFoundError("Schema", parameters[0]);
+                } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
+                    schemaResultManager.generic("You cannot delete schema " + parameters[0]);
+                } else {
+                    schemaResultManager.generic(ex.getMessage());
+                }
+            } catch (final IllegalArgumentException ex) {
+                schemaResultManager.typeNotValidError(
+                        "schema", input.firstParameter(), CommandUtils.fromEnumToArray(SchemaType.class));
+            }
+        } else {
+            schemaResultManager.commandOptionError(DELETE_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaList.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaList.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaList.java
new file mode 100644
index 0000000..5f51604
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaList.java
@@ -0,0 +1,70 @@
+/*
+ * 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.cli.commands.schema;
+
+import java.util.LinkedList;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.util.CommandUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.types.SchemaType;
+
+public class SchemaList extends AbstractSchemaCommand {
+
+    private static final String LIST_HELP_MESSAGE = "schema --list {SCHEMA-TYPE}\n"
+            + "   Schema type: PLAIN / DERIVED / VIRTUAL";
+
+    private final Input input;
+
+    public SchemaList(final Input input) {
+        this.input = input;
+    }
+
+    public void list() {
+        if (input.parameterNumber() == 1) {
+            try {
+                final SchemaType schemaType = SchemaType.valueOf(input.firstParameter());
+                final LinkedList<AbstractSchemaTO> schemaTOs = new LinkedList<>();
+                for (final AbstractSchemaTO schemaTO : schemaService.list(schemaType)) {
+                    schemaTOs.add(schemaTO);
+                }
+                switch (schemaType) {
+                    case PLAIN:
+                        schemaResultManager.fromListPlain(schemaTOs);
+                        break;
+                    case DERIVED:
+                        schemaResultManager.fromListDerived(schemaTOs);
+                        break;
+                    case VIRTUAL:
+                        schemaResultManager.fromListVirtual(schemaTOs);
+                        break;
+                    default:
+                        break;
+                }
+            } catch (final SyncopeClientException ex) {
+                schemaResultManager.generic(ex.getMessage());
+            } catch (final IllegalArgumentException ex) {
+                schemaResultManager.typeNotValidError(
+                        "schema", input.firstParameter(), CommandUtils.fromEnumToArray(SchemaType.class));
+            }
+        } else {
+            schemaResultManager.commandOptionError(LIST_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListAll.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListAll.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListAll.java
new file mode 100644
index 0000000..5d00adb
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListAll.java
@@ -0,0 +1,55 @@
+/*
+ * 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.cli.commands.schema;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.types.SchemaType;
+
+public class SchemaListAll extends AbstractSchemaCommand {
+
+    public void listAll() {
+        try {
+            for (final SchemaType schemaType : SchemaType.values()) {
+                final LinkedList<AbstractSchemaTO> schemaTOs = new LinkedList<>();
+                for (final AbstractSchemaTO schemaTO : schemaService.list(schemaType)) {
+                    schemaTOs.add(schemaTO);
+                }
+                switch (schemaType) {
+                    case PLAIN:
+                        schemaResultManager.fromListPlain(schemaTOs);
+                        break;
+                    case DERIVED:
+                        schemaResultManager.fromListDerived(schemaTOs);
+                        break;
+                    case VIRTUAL:
+                        schemaResultManager.fromListVirtual(schemaTOs);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        } catch (final SyncopeClientException | WebServiceException ex) {
+            schemaResultManager.generic(ex.getMessage());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListDerived.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListDerived.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListDerived.java
new file mode 100644
index 0000000..8cdb501
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListDerived.java
@@ -0,0 +1,40 @@
+/*
+ * 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.cli.commands.schema;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.types.SchemaType;
+
+public class SchemaListDerived extends AbstractSchemaCommand {
+
+    public void listDerived() {
+        try {
+            final LinkedList<AbstractSchemaTO> schemaTOs = new LinkedList<>();
+            for (final AbstractSchemaTO schemaTO : schemaService.list(SchemaType.DERIVED)) {
+                schemaTOs.add(schemaTO);
+            }
+            schemaResultManager.fromListDerived(schemaTOs);
+        } catch (final SyncopeClientException | WebServiceException ex) {
+            schemaResultManager.generic(ex.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListPlain.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListPlain.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListPlain.java
new file mode 100644
index 0000000..e4160a7
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListPlain.java
@@ -0,0 +1,40 @@
+/*
+ * 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.cli.commands.schema;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.types.SchemaType;
+
+public class SchemaListPlain extends AbstractSchemaCommand {
+
+    public void listPlain() {
+        try {
+            final LinkedList<AbstractSchemaTO> schemaTOs = new LinkedList<>();
+            for (final AbstractSchemaTO schemaTO : schemaService.list(SchemaType.PLAIN)) {
+                schemaTOs.add(schemaTO);
+            }
+            schemaResultManager.fromListPlain(schemaTOs);
+        } catch (final SyncopeClientException | WebServiceException ex) {
+            schemaResultManager.generic(ex.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListVirtual.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListVirtual.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListVirtual.java
new file mode 100644
index 0000000..7b1bf24
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaListVirtual.java
@@ -0,0 +1,40 @@
+/*
+ * 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.cli.commands.schema;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.types.SchemaType;
+
+public class SchemaListVirtual extends AbstractSchemaCommand {
+
+    public void listVirtual() {
+        try {
+            final LinkedList<AbstractSchemaTO> schemaTOs = new LinkedList<>();
+            for (final AbstractSchemaTO schemaTO : schemaService.list(SchemaType.VIRTUAL)) {
+                schemaTOs.add(schemaTO);
+            }
+            schemaResultManager.fromListVirtual(schemaTOs);
+        } catch (final SyncopeClientException | WebServiceException ex) {
+            schemaResultManager.generic(ex.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaRead.java
new file mode 100644
index 0000000..97f1029
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaRead.java
@@ -0,0 +1,78 @@
+/*
+ * 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.cli.commands.schema;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.util.CommandUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.types.SchemaType;
+
+public class SchemaRead extends AbstractSchemaCommand {
+
+    private static final String READ_HELP_MESSAGE = "schema --read {SCHEMA-TYPE} {SCHEMA-KEY}\n"
+            + "   Schema type: PLAIN / DERIVED / VIRTUAL";
+
+    private final Input input;
+
+    public SchemaRead(final Input input) {
+        this.input = input;
+    }
+
+    public void read() {
+        if (input.parameterNumber() >= 2) {
+            final String[] parameters = Arrays.copyOfRange(input.getParameters(), 1, input.parameterNumber());
+            try {
+                final SchemaType schemaType = SchemaType.valueOf(input.firstParameter());
+                final LinkedList<AbstractSchemaTO> schemaTOs = new LinkedList<>();
+                for (final String parameter : parameters) {
+                    schemaTOs.add(schemaService.read(schemaType, parameter));
+                }
+                switch (schemaType) {
+                    case PLAIN:
+                        schemaResultManager.fromReadPlain(schemaTOs);
+                        break;
+                    case DERIVED:
+                        schemaResultManager.fromListDerived(schemaTOs);
+                        break;
+                    case VIRTUAL:
+                        schemaResultManager.fromListVirtual(schemaTOs);
+                        break;
+                    default:
+                        break;
+                }
+            } catch (final SyncopeClientException | WebServiceException ex) {
+                if (ex.getMessage().startsWith("NotFound")) {
+                    schemaResultManager.notFoundError("Schema", parameters[0]);
+                } else {
+                    schemaResultManager.generic(ex.getMessage());
+                }
+            } catch (final IllegalArgumentException ex) {
+                schemaResultManager.typeNotValidError(
+                        "schema", input.firstParameter(), CommandUtils.fromEnumToArray(SchemaType.class));
+            }
+        } else {
+            schemaResultManager.commandOptionError(READ_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaResultManager.java
new file mode 100644
index 0000000..8880dd3
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/schema/SchemaResultManager.java
@@ -0,0 +1,96 @@
+/*
+ * 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.cli.commands.schema;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+import org.apache.syncope.client.cli.messages.Table;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.to.DerSchemaTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.VirSchemaTO;
+
+public class SchemaResultManager extends CommonsResultManager {
+
+    public void fromListPlain(final LinkedList<? extends AbstractSchemaTO> schemaTOs) {
+        final Table.TableBuilder tableBuilder
+                = new Table.TableBuilder("plain schemas").header("schema key").header("type").header("mandatory");
+        for (final AbstractSchemaTO schemaTO : schemaTOs) {
+            tableBuilder.rowValues(new LinkedList(Arrays.asList(
+                    ((PlainSchemaTO) schemaTO).getKey(),
+                    ((PlainSchemaTO) schemaTO).getType().toString(),
+                    ((PlainSchemaTO) schemaTO).getMandatoryCondition())));
+        }
+        tableBuilder.build().print();
+    }
+
+    public void fromReadPlain(final LinkedList<? extends AbstractSchemaTO> schemaTOs) {
+        final Table.TableBuilder tableBuilder
+                = new Table.TableBuilder("plain schema details ")
+                .header("schema key")
+                .header("type class")
+                .header("pattern")
+                .header("enum keys")
+                .header("enum values")
+                .header("mandatory condition")
+                .header("mime type")
+                .header("secret key")
+                .header("class validator")
+                .header("chiper")
+                .header("type");
+        for (final AbstractSchemaTO schemaTO : schemaTOs) {
+            tableBuilder.rowValues(new LinkedList(Arrays.asList(
+                    ((PlainSchemaTO) schemaTO).getKey(),
+                    ((PlainSchemaTO) schemaTO).getAnyTypeClass(),
+                    ((PlainSchemaTO) schemaTO).getConversionPattern(),
+                    ((PlainSchemaTO) schemaTO).getEnumerationKeys(),
+                    ((PlainSchemaTO) schemaTO).getEnumerationValues(),
+                    ((PlainSchemaTO) schemaTO).getMandatoryCondition(),
+                    ((PlainSchemaTO) schemaTO).getMimeType(),
+                    ((PlainSchemaTO) schemaTO).getSecretKey(),
+                    ((PlainSchemaTO) schemaTO).getValidatorClass(),
+                    ((PlainSchemaTO) schemaTO).getCipherAlgorithm(),
+                    ((PlainSchemaTO) schemaTO).getType().toString())));
+        }
+        tableBuilder.build().print();
+    }
+
+    public void fromListDerived(final LinkedList<? extends AbstractSchemaTO> schemaTOs) {
+        final Table.TableBuilder tableBuilder
+                = new Table.TableBuilder("derived schemas").header("schema key").header("expression");
+        for (final AbstractSchemaTO schemaTO : schemaTOs) {
+            tableBuilder.rowValues(new LinkedList(Arrays.asList(
+                    ((DerSchemaTO) schemaTO).getKey(),
+                    ((DerSchemaTO) schemaTO).getExpression())));
+        }
+        tableBuilder.build().print();
+    }
+
+    public void fromListVirtual(final LinkedList<? extends AbstractSchemaTO> schemaTOs) {
+        final Table.TableBuilder tableBuilder
+                = new Table.TableBuilder("virtual schemas").header("schema key").header("readonly");
+        for (final AbstractSchemaTO schemaTO : schemaTOs) {
+            tableBuilder.rowValues(new LinkedList(Arrays.asList(
+                    ((VirSchemaTO) schemaTO).getKey(),
+                    String.valueOf(((VirSchemaTO) schemaTO).isReadonly()))));
+        }
+        tableBuilder.build().print();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/80f2548a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
index 8a28965..311682c 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
@@ -94,7 +94,7 @@ public final class Table {
 
         for (final LinkedList<String> value : values) {
             for (int j = 0; j < columnsSize.length; j++) {
-                if (value.get(j).length() > columnsSize[j]) {
+                if (value.get(j) != null && value.get(j).length() > columnsSize[j]) {
                     columnsSize[j] = value.get(j).length();
                 }
             }
@@ -143,9 +143,13 @@ public final class Table {
     private void printeContent() {
         printColumnSpace();
 
-        for (LinkedList<String> value : values) {
+        for (final LinkedList<String> value : values) {
             for (int j = 0; j < columnsNumber; j++) {
-                tmpValuesArray[j] = StringUtils.center(value.get(j), columnsSize[j]);
+                if (value.get(j) == null) {
+                    tmpValuesArray[j] = StringUtils.center("null", columnsSize[j]);
+                } else {
+                    tmpValuesArray[j] = StringUtils.center(value.get(j), columnsSize[j]);
+                }
             }
             System.out.format(tableContentFormat, tmpValuesArray);
         }
@@ -160,7 +164,7 @@ public final class Table {
 
         System.out.format(tableContentFormat, tmpValuesArray);
     }
-    
+
     public static class TableBuilder {
 
         private final LinkedList<String> headers = new LinkedList<>();


[10/54] [abbrv] syncope git commit: Finishing documentation review

Posted by fm...@apache.org.
Finishing documentation review


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

Branch: refs/heads/SYNCOPE-156
Commit: 405f212346b7714f1b21c67d37e35d9cf1e30809
Parents: 56e05c6
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Thu Oct 15 16:15:49 2015 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Thu Oct 15 16:15:49 2015 +0100

----------------------------------------------------------------------
 src/main/asciidoc/obtain.adoc             | 42 +++++++++++++-------------
 src/main/asciidoc/systemRequirements.adoc |  6 ++--
 2 files changed, 24 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/405f2123/src/main/asciidoc/obtain.adoc
----------------------------------------------------------------------
diff --git a/src/main/asciidoc/obtain.adoc b/src/main/asciidoc/obtain.adoc
index 4ca2c6c..b318964 100644
--- a/src/main/asciidoc/obtain.adoc
+++ b/src/main/asciidoc/obtain.adoc
@@ -19,11 +19,11 @@
 
 == Obtain Apache Syncope
 
-There are several ways to obtain Apache Syncope: each method shows advantages or caveats for different types of users.
+There are several ways to obtain Apache Syncope: each of which has advantages or caveats for different types of users.
 
 === Standalone
 
-The standalone distribution is the simpler way to start exploring Apache Syncope: it contains a full working, in-memory
+The standalone distribution is the simplest way to start exploring Apache Syncope: it contains a fully working, in-memory
 Tomcat-based environment that can be easily grabbed and put at work on any modern laptop, workstation or server. 
 
 [CAUTION]
@@ -31,7 +31,7 @@ Tomcat-based environment that can be easily grabbed and put at work on any moder
 First approach, especially with administration console; does not require technical skills. +
 *Not meant for any production environment.*
 
-Getting ready in few easy steps:
+Getting ready in a few easy steps:
 
 . http://syncope.apache.org/downloads.html[download^] the standalone distribution
 . unzip the distribution archive
@@ -53,19 +53,19 @@ $ ./bin/startup.sh
 ----
 
 [TIP]
-Please refer to http://tomcat.apache.org/tomcat-8.0-doc/[Apache Tomcat documentation^] for more advanced setup and 
+Please refer to the http://tomcat.apache.org/tomcat-8.0-doc/[Apache Tomcat documentation^] for more advanced setup and 
 instructions.
 
 ==== Components
 
 The set of available components, including access URLs and credentials, is the same as reported for 
-<<paths-and-components,embedded mode>>, with exception of log files, here available under `$CATALINA_HOME/logs`.
+<<paths-and-components,embedded mode>>, with the exception of log files, available here under `$CATALINA_HOME/logs`.
 
 [TIP]
 .Internal Storage
 ====
-By default, the standalone distribution is configured for using an in-memory database instance.
-This means that every time Tomcat is shut down all changes made are lost.
+By default, the standalone distribution is configured to use an in-memory database instance.
+This means that every time Tomcat is shut down all changes that have been made are lost.
 
 If you want instead to make your changes persistent, replace
 
@@ -80,12 +80,12 @@ jpa.url=jdbc:h2:~/syncopedb;DB_CLOSE_DELAY=-1
 in `webapps/syncope/WEB-INF/classes/persistence.properties` from the Apache Tomcat directory.
 This will create H2 database files in the home directory of the user running Apache Syncope.
 
-Please refer to http://www.h2database.com/[H2 documentation^] for more options.
+Please refer to the http://www.h2database.com/[H2 documentation^] for more options.
 ====
 
 === Debian packages
 
-Debian packages are available for usage with latest http://www.debian.org/[Debian GNU / Linux^], 
+Debian packages are available for use with http://www.debian.org/[Debian GNU / Linux^], 
 http://www.ubuntu.com/[Ubuntu^] and their derivatives. 
 
 [CAUTION]
@@ -126,7 +126,7 @@ sudo service tomcat8 stop
 [source,bash]
 sudo dpkg -i apache-syncope-*.deb
 +
-. Create a database for usage with Apache Syncope
+. Create a database for use with Apache Syncope
 +
 [source,bash]
 sudo SYNCOPE_USER="syncope" SYNCOPE_PASS="syncope" sh /usr/share/apache-syncope/dbinit-postgresql.sh
@@ -162,16 +162,16 @@ GUI application for configuring and deploying Apache Syncope on supported
 
 [CAUTION]
 .Target Audience
-Getting up and running quickly on any supported DBMS and Java EE container, independently from underlying
+Getting up and running quickly on any supported DBMS and Java EE container, independently from the underlying
 operating system. +
 *Difficult to extend beyond pre-sets.*
 
 ==== Prerequisites
 
  . http://maven.apache.org/[Apache Maven^] (version 3.0.3 or higher) installed
- . one of supported <<internal-storage,DBMSes>> up and running
- . one of supported <<java-ee-container, Java EE containers>> up and running 
- . datasource with name `syncopeDataSource` configured in the selected Java EE container, for a database instance in the
+ . one of the supported <<internal-storage,DBMSes>> up and running
+ . one of the supported <<java-ee-container, Java EE containers>> up and running 
+ . A datasource with the name `syncopeDataSource` configured in the selected Java EE container, for a database instance in the
  DBMS of choice
 
 [WARNING]
@@ -192,7 +192,7 @@ of `$CATALINA_HOME/conf/tomcat-users.xml` looks like:
 
 ==== Usage
 
-Once http://syncope.apache.org/downloads.html[downloaded^], double-click the JAR file or execute via command-line:
+Once http://syncope.apache.org/downloads.html[downloaded^], double-click the JAR file or execute via the command-line:
 
 [source,bash]
 java -jar syncope-installer-*-uber.jar
@@ -213,7 +213,7 @@ Maven home directory:: directory where Apache Maven is installed
 GroupId:: something like 'com.mycompany'
 ArtifactId:: something like 'mySyncopeProject'
 Secret Key:: provide any pseudo-random string here that will be used in the generated project for AES ciphering
-Anonymous Key:: provide any pseudo-random string here that will be used an authentication key for anonymous requests
+Anonymous Key:: provide any pseudo-random string here that will be used as an authentication key for anonymous requests
 Configuration directory:: directory for configuration files
 Log directory:: directory for log files
 Bundle directory:: directory where ConnId bundles are put
@@ -255,7 +255,7 @@ and extension capabilities.
 
 [CAUTION]
 .Target Audience
-Provides access to full capabilities of Apache Syncope, and nearly any possible extension. +
+Provides access to the full capabilities of Apache Syncope, and almost all extensions that are possible. +
 *Requires Apache Maven (and potentially https://en.wikipedia.org/wiki/DevOps[DevOps^]) skills.*
 
 ==== Prerequisites
@@ -315,7 +315,7 @@ generated project:
 
 endif::[]
 
-The archetype is configured with default values for all properties required; if you want to customize any of these 
+The archetype is configured with default values for all required properties; if you want to customize any of these 
 property values, type 'n' when prompted for confirmation.
 
 You will be asked for:
@@ -333,7 +333,7 @@ to the groupId.
 secretKey::
     Provide any pseudo-random string here that will be used in the generated project for AES ciphering.
 anonymousKey:: 
-    Provide any pseudo-random string here that will be used an authentication key for anonymous requests.
+    Provide any pseudo-random string here that will be used as an authentication key for anonymous requests.
 
 Maven will create a project for you (in a newly created directory named after the value of the `artifactId` property 
 specified above) containing three modules: `common`, `core` and `console`.
@@ -343,12 +343,12 @@ You are now able to perform the first build via
 [source,bash]
 mvn clean verify
 
-After downloading all the needed dependencies, this will produce two WAR files:
+After downloading all of the needed dependencies, two WAR files will be produced:
 
 . `core/target/syncope.war`
 . `console/target/syncope-console.war`
 
-If no failures are encountered, your basic Apache Syncope project is now set.
+If no failures are encountered, your basic Apache Syncope project is now ready to go.
 
 [NOTE]
 You should consider reading the _Apache Syncope Reference Guide_ for understanding how to configure, extend, customize 

http://git-wip-us.apache.org/repos/asf/syncope/blob/405f2123/src/main/asciidoc/systemRequirements.adoc
----------------------------------------------------------------------
diff --git a/src/main/asciidoc/systemRequirements.adoc b/src/main/asciidoc/systemRequirements.adoc
index a18534e..c9bf7bf 100644
--- a/src/main/asciidoc/systemRequirements.adoc
+++ b/src/main/asciidoc/systemRequirements.adoc
@@ -21,7 +21,7 @@
 
 === Hardware
 
-The numbers below are greatly affected by several requirements of given deployment, in particular the total number of
+The hardware requirements depend greatly on the given deployment, in particular the total number of
 managed entities (users, groups and any objects), their attributes and resources.
 
  * CPU: dual core, 2 GHz (minimum)
@@ -30,7 +30,7 @@ managed entities (users, groups and any objects), their attributes and resources
 
 === Java
 
-Apache Syncope {docVersion} requires the latest JDK 7 or JDK 8 available.
+Apache Syncope {docVersion} requires the latest JDK 7 or JDK 8 that is available.
 
 === Java EE Container
 
@@ -48,4 +48,4 @@ Apache Syncope {docVersion} is verified with the recent versions of the followin
  . https://mariadb.org/[MariaDB^]
  . http://www.mysql.com/[MySQL^]
  . https://www.oracle.com/database/index.html[Oracle Database^]
- . http://www.microsoft.com/en-us/server-cloud/products/sql-server/[MS SQL Server^]
\ No newline at end of file
+ . http://www.microsoft.com/en-us/server-cloud/products/sql-server/[MS SQL Server^]


[19/54] [abbrv] syncope git commit: Upgrading surefire, failsafe and checkstyle plugins

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
index 2178d22,0000000..c6bdb48
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
@@@ -1,351 -1,0 +1,351 @@@
 +/*
 + * 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.cli.commands;
 +
 +import java.io.IOException;
 +import java.io.SequenceInputStream;
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.List;
 +import javax.xml.parsers.ParserConfigurationException;
 +import javax.xml.transform.TransformerException;
 +import javax.xml.ws.WebServiceException;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.SyncopeServices;
 +import org.apache.syncope.client.cli.messages.Messages;
 +import org.apache.syncope.client.cli.util.XMLUtils;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.to.ReportExecTO;
 +import org.apache.syncope.common.lib.to.ReportTO;
 +import org.apache.syncope.common.lib.types.JobStatusType;
 +import org.apache.syncope.common.lib.types.ReportExecExportFormat;
 +import org.apache.syncope.common.rest.api.service.ReportService;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.xml.sax.SAXException;
 +
 +@Command(name = "report")
 +public class ReportCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(ReportCommand.class);
 +
 +    private static final String HELP_MESSAGE = "Usage: report [options]\n"
 +            + "  Options:\n"
 +            + "    --help \n"
 +            + "    --list \n"
 +            + "    --read \n"
 +            + "       Syntax: --read {REPORT-ID} {REPORT-ID} [...] \n"
 +            + "    --delete \n"
 +            + "       Syntax: --delete {REPORT-ID} {REPORT-ID} [...]\n"
 +            + "    --execute \n"
 +            + "       Syntax: --execute {REPORT-ID} \n"
 +            + "    --read-execution \n"
 +            + "       Syntax: --read-execution {EXECUTION-ID} {EXECUTION-ID} [...]\n"
 +            + "    --delete-execution \n"
 +            + "       Syntax: --delete-execution {EXECUTION-ID} {EXECUTION-ID} [...]\n"
 +            + "    --export-execution-result \n"
 +            + "       Syntax: --export-execution-result {EXECUTION-ID} {EXECUTION-ID} [...] {FORMAT}\n"
 +            + "          Format: CSV / HTML / PDF / XML / RTF"
 +            + "    --reportlet-class";
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        String[] parameters = input.getParameters();
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        final ReportService reportService = SyncopeServices.get(ReportService.class);
 +        switch (Options.fromName(input.getOption())) {
 +            case LIST:
 +                try {
 +                    for (final ReportTO reportTO : reportService.list()) {
 +                        System.out.println(reportTO);
 +                    }
 +                } catch (final SyncopeClientException ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                }
 +                break;
 +            case LIST_JOBS:
 +                try {
 +                    for (final JobStatusType jobStatusType : JobStatusType.values()) {
 +                        System.out.println("Report execution for " + jobStatusType);
 +                        final List<ReportExecTO> reportExecTOs = reportService.listJobs(jobStatusType);
 +                        for (final ReportExecTO reportExecTO : reportExecTOs) {
 +                            System.out.println(" - Report execution id: " + reportExecTO.getKey());
 +                            System.out.println(" - Report execution status: " + reportExecTO.getStatus());
 +                            System.out.println(" - Report execution start date: " + reportExecTO.getStartDate());
 +                            System.out.println(" - Report execution end date: " + reportExecTO.getEndDate());
 +                            System.out.println();
 +                        }
 +                    }
 +                } catch (final SyncopeClientException ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                }
 +                break;
 +            case READ:
 +                final String readErrorMessage = "report --read {REPORT-ID} {REPORT-ID} [...]";
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            System.out.println(reportService.read(Long.valueOf(parameter)));
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("report", parameter);
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Report", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(readErrorMessage);
 +                }
 +                break;
 +            case DELETE:
 +                final String deleteErrorMessage = "report --delete {REPORT-ID} {REPORT-ID} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            reportService.delete(Long.valueOf(parameter));
 +                            Messages.printDeletedMessage("Report", parameter);
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Report", parameter);
 +                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
 +                                Messages.printMessage("You cannot delete report " + parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("report", parameter);
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(deleteErrorMessage);
 +                }
 +                break;
 +            case EXECUTE:
 +                final String executeErrorMessage = "report --execute {REPORT-ID}";
 +
 +                if (parameters.length == 1) {
 +
 +                    try {
 +                        final Long reportIdToExecute = Long.valueOf(parameters[0]);
 +                        reportService.execute(reportIdToExecute);
 +                        final List<ReportExecTO> executionList
 +                                = reportService.read(reportIdToExecute).getExecutions();
 +                        final ReportExecTO lastExecution = executionList.get(executionList.size() - 1);
 +                        System.out.println(" - Report execution id: " + lastExecution.getKey());
 +                        System.out.println(" - Report execution status: " + lastExecution.getStatus());
 +                        System.out.println(" - Report execution start date: " + lastExecution.getStartDate());
 +                    } catch (final WebServiceException | SyncopeClientException ex) {
 +                        System.out.println("Error:");
 +                        if (ex.getMessage().startsWith("NotFound")) {
 +                            Messages.printNofFoundMessage("Report", parameters[0]);
 +                        } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
 +                            Messages.printMessage("You cannot delete report " + parameters[0]);
 +                        } else {
 +                            Messages.printMessage(ex.getMessage());
 +                        }
 +                    } catch (final NumberFormatException ex) {
 +                        Messages.printIdNotNumberDeletedMessage("report", parameters[0]);
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(executeErrorMessage);
 +                }
 +                break;
 +            case READ_EXECUTION:
 +                final String readExecutionErrorMessage = "report --read-execution {EXECUTION-ID} {EXECUTION-ID} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +
 +                        try {
 +                            ReportExecTO reportExecTO = reportService.readExecution(Long.valueOf(parameter));
 +                            System.out.println(" - Report execution id: " + reportExecTO.getKey());
 +                            System.out.println(" - Report execution status: " + reportExecTO.getStatus());
 +                            System.out.println(" - Report execution start date: " + reportExecTO.getStartDate());
 +                            System.out.println(" - Report execution end date: " + reportExecTO.getEndDate());
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            System.out.println("Error:");
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Report", parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("report", parameter);
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(readExecutionErrorMessage);
 +                }
 +                break;
 +            case DELETE_EXECUTION:
 +                final String deleteExecutionErrorMessage
 +                        = "report --delete-execution {EXECUTION-ID} {EXECUTION-ID} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +
 +                        try {
 +                            reportService.deleteExecution(Long.valueOf(parameter));
 +                            Messages.printDeletedMessage("Report execution", parameter);
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Report", parameter);
 +                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
 +                                System.out.println(" - You cannot delete report " + parameter);
 +                            } else {
 +                                System.out.println(ex.getMessage());
 +                            }
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("report", parameter);
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(deleteExecutionErrorMessage);
 +                }
 +                break;
 +            case EXPORT_EXECUTION_RESULT:
 +                final String exportExecutionErrorMessage
 +                        = "report --export-execution-result {EXECUTION-ID} {EXECUTION-ID} [...] {FORMAT}\n"
 +                        + "          Format: CSV / HTML / PDF / XML / RTF";
 +
 +                if (parameters.length >= 2) {
 +                    parameters = Arrays.copyOf(parameters, parameters.length - 1);
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            final ReportExecExportFormat format = ReportExecExportFormat.valueOf(input.lastParameter());
 +                            final Long exportId = Long.valueOf(parameter);
 +                            final SequenceInputStream report = (SequenceInputStream) reportService.
 +                                    exportExecutionResult(exportId, format).getEntity();
 +                            switch (format) {
 +                                case XML:
 +                                    final String xmlFinalName = "export_" + exportId + ".xml";
 +                                    XMLUtils.createXMLFile(report, xmlFinalName);
 +                                    Messages.printMessage(xmlFinalName + " successfully created");
 +                                    break;
 +                                case CSV:
 +                                    Messages.printMessage(format + " doesn't supported");
 +                                    break;
 +                                case PDF:
 +                                    Messages.printMessage(format + " doesn't supported");
 +                                    break;
 +                                case HTML:
 +                                    Messages.printMessage(format + " doesn't supported");
 +                                    break;
 +                                case RTF:
 +                                    Messages.printMessage(format + " doesn't supported");
 +                                    break;
 +                                default:
 +                                    Messages.printMessage(format + " doesn't supported");
 +                                    break;
 +                            }
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Report", parameter);
 +                            } else {
 +                                System.out.println(ex.getMessage());
 +                            }
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("report", parameter);
 +                        } catch (IOException | ParserConfigurationException | SAXException | TransformerException e) {
 +                            System.out.println(" - Error creating " + "export_" + parameter + " " + e.getMessage());
 +                        } catch (final IllegalArgumentException ex) {
 +                            Messages.printTypeNotValidMessage(
 +                                    "format", input.firstParameter(),
 +                                    fromEnumToArray(ReportExecExportFormat.class));
 +                        }
 +                        break;
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(exportExecutionErrorMessage);
 +                }
 +                break;
 +            case HELP:
 +                System.out.println(HELP_MESSAGE);
 +                break;
 +            default:
 +                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
 +        }
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return HELP_MESSAGE;
 +    }
 +
 +    private enum Options {
 +
 +        HELP("--help"),
 +        LIST("--list"),
 +        LIST_JOBS("--list-jobs"),
 +        READ("--read"),
 +        DELETE("--delete"),
 +        EXECUTE("--execute"),
 +        READ_EXECUTION("--read-execution"),
 +        DELETE_EXECUTION("--delete-execution"),
 +        EXPORT_EXECUTION_RESULT("--export-execution-result");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +
 +        public static List<String> toList() {
 +            final List<String> options = new ArrayList<>();
 +            for (final Options value : values()) {
 +                options.add(value.getOptionName());
 +            }
 +            return options;
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
index 7cb9ca1,0000000..826d8dc
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
@@@ -1,308 -1,0 +1,308 @@@
 +/*
 + * 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.cli.commands;
 +
 +import static org.apache.syncope.client.cli.commands.AbstractCommand.fromEnumToArray;
 +
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.List;
 +import javax.xml.ws.WebServiceException;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.SyncopeServices;
 +import org.apache.syncope.client.cli.messages.Messages;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.to.AbstractSchemaTO;
 +import org.apache.syncope.common.lib.to.DerSchemaTO;
 +import org.apache.syncope.common.lib.to.PlainSchemaTO;
 +import org.apache.syncope.common.lib.to.VirSchemaTO;
 +import org.apache.syncope.common.lib.types.SchemaType;
 +import org.apache.syncope.common.rest.api.service.SchemaService;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +@Command(name = "schema")
 +public class SchemaCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(SchemaCommand.class);
 +
 +    private static final String HELP_MESSAGE = "Usage: schema [options]\n"
 +            + "  Options:\n"
 +            + "    --help \n"
 +            + "    --list-all\n"
 +            + "    --list-plain\n"
 +            + "    --list-derived\n"
 +            + "    --list-virtual\n"
 +            + "    --list {SCHEMA-TYPE}\n"
 +            + "       Schema type: PLAIN / DERIVED / VIRTUAL";
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        String[] parameters = input.getParameters();
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        final SchemaService schemaService = SyncopeServices.get(SchemaService.class);
 +        switch (Options.fromName(input.getOption())) {
 +            case LIST:
 +                final String listErrorMessage = "schema --list {SCHEMA-TYPE}\n"
 +                        + "   Schema type: PLAIN / DERIVED / VIRTUAL";
 +                if (parameters.length == 1) {
 +                    try {
 +                        final SchemaType schemaType = SchemaType.valueOf(input.firstParameter());
 +                        System.out.println("");
 +                        for (final AbstractSchemaTO schemaTO : schemaService.list(schemaType)) {
 +                            switch (schemaType) {
 +                                case PLAIN:
 +                                    System.out.println(" - Schema key: " + ((PlainSchemaTO) schemaTO).getKey());
 +                                    System.out.println("      type: " + ((PlainSchemaTO) schemaTO).getType());
 +                                    System.out.println("      is mandatory: "
 +                                            + ((PlainSchemaTO) schemaTO).getMandatoryCondition());
 +                                    break;
 +                                case DERIVED:
 +                                    System.out.println(" - Schema key: " + ((DerSchemaTO) schemaTO).getKey());
 +                                    System.out.println("      expression: " + ((DerSchemaTO) schemaTO).getExpression());
 +                                    break;
 +                                case VIRTUAL:
 +                                    System.out.println(" - Schema key: " + ((VirSchemaTO) schemaTO).getKey());
 +                                    break;
 +                                default:
 +                                    break;
 +                            }
 +                        }
 +                        System.out.println("");
 +                    } catch (final SyncopeClientException ex) {
 +                        Messages.printMessage(ex.getMessage());
 +                    } catch (final IllegalArgumentException ex) {
 +                        Messages.printTypeNotValidMessage(
 +                                "schema", input.firstParameter(), fromEnumToArray(SchemaType.class));
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(listErrorMessage);
 +                }
 +                break;
 +            case LIST_ALL:
 +                try {
 +                    for (final SchemaType value : SchemaType.values()) {
 +                        System.out.println("");
 +                        System.out.println(value + " schemas");
 +                        for (final AbstractSchemaTO schemaTO : schemaService.list(value)) {
 +                            System.out.println("   - Name: " + schemaTO.getKey() + " type: "
 +                                    + schemaTO.getAnyTypeClass());
 +                        }
 +                        System.out.println("");
 +                    }
 +                } catch (final SyncopeClientException | WebServiceException ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                }
 +                break;
 +            case LIST_PLAIN:
 +                try {
 +                    System.out.println("");
 +                    for (final AbstractSchemaTO schemaTO : schemaService.list(SchemaType.PLAIN)) {
 +                        System.out.println(" - Schema key: " + ((PlainSchemaTO) schemaTO).getKey());
 +                        System.out.println("      type: " + ((PlainSchemaTO) schemaTO).getType());
 +                        System.out.println("      is mandatory: "
 +                                + ((PlainSchemaTO) schemaTO).getMandatoryCondition());
 +                    }
 +                    System.out.println("");
 +                } catch (final SyncopeClientException | WebServiceException ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                }
 +                break;
 +            case LIST_DERIVED:
 +                try {
 +                    System.out.println("");
 +                    for (final AbstractSchemaTO schemaTO : schemaService.list(SchemaType.DERIVED)) {
 +                        System.out.println(" - Schema key: " + ((DerSchemaTO) schemaTO).getKey());
 +                        System.out.println("      expression: " + ((DerSchemaTO) schemaTO).getExpression());
 +                    }
 +                    System.out.println("");
 +                } catch (final SyncopeClientException | WebServiceException ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                }
 +                break;
 +            case LIST_VIRTUAL:
 +                try {
 +                    System.out.println("");
 +                    for (final AbstractSchemaTO schemaTO : schemaService.list(SchemaType.VIRTUAL)) {
 +                        System.out.println(" - Schema key: " + ((VirSchemaTO) schemaTO).getKey());
 +                    }
 +                    System.out.println("");
 +                } catch (final SyncopeClientException | WebServiceException ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                }
 +                break;
 +            case READ:
 +                final String readErrorMessage = "schema --read {SCHEMA-TYPE} {SCHEMA-KEY}\n"
 +                        + "   Schema type: PLAIN / DERIVED / VIRTUAL";
 +                if (parameters.length >= 2) {
 +                    parameters = Arrays.copyOfRange(parameters, 1, parameters.length);
 +                    try {
 +                        final SchemaType schemaType = SchemaType.valueOf(input.firstParameter());
 +                        System.out.println("");
 +                        for (final String parameter : parameters) {
 +                            final AbstractSchemaTO schemaTO = schemaService.read(schemaType, parameter);
 +                            switch (schemaType) {
 +                                case PLAIN:
 +                                    System.out.println(" - Schema key: " + ((PlainSchemaTO) schemaTO).getKey());
 +                                    System.out.println("      any type class: "
 +                                            + ((PlainSchemaTO) schemaTO).getAnyTypeClass());
 +                                    System.out.println("      conversion pattern: "
 +                                            + ((PlainSchemaTO) schemaTO).getConversionPattern());
 +                                    System.out.println("      enumeration keys: "
 +                                            + ((PlainSchemaTO) schemaTO).getEnumerationKeys());
 +                                    System.out.println("      enumeration values: "
 +                                            + ((PlainSchemaTO) schemaTO).getEnumerationValues());
 +                                    System.out.println("      mandatory condition: "
 +                                            + ((PlainSchemaTO) schemaTO).getMandatoryCondition());
 +                                    System.out.println("      mime type: " + ((PlainSchemaTO) schemaTO).getMimeType());
 +                                    System.out.println("      secret key: "
 +                                            + ((PlainSchemaTO) schemaTO).getSecretKey());
 +                                    System.out.println("      validator class: "
 +                                            + ((PlainSchemaTO) schemaTO).getValidatorClass());
 +                                    System.out.println("      cipher algorithm: "
 +                                            + ((PlainSchemaTO) schemaTO).getCipherAlgorithm());
 +                                    System.out.println("      TYPE: "
 +                                            + ((PlainSchemaTO) schemaTO).getType());
 +                                    break;
 +                                case DERIVED:
 +                                    System.out.println(" - Schema key: " + ((DerSchemaTO) schemaTO).getKey());
 +                                    System.out.println("      any type class: "
 +                                            + ((DerSchemaTO) schemaTO).getAnyTypeClass());
 +                                    System.out.println("      expression: " + ((DerSchemaTO) schemaTO).getExpression());
 +                                    break;
 +                                case VIRTUAL:
 +                                    System.out.println(" - Schema key: " + ((VirSchemaTO) schemaTO).getKey());
 +                                    System.out.println("      any type class: "
 +                                            + ((VirSchemaTO) schemaTO).getAnyTypeClass());
 +                                    break;
 +                                default:
 +                                    break;
 +                            }
 +                            System.out.println("");
 +                        }
 +                    } catch (final SyncopeClientException | WebServiceException ex) {
 +                        if (ex.getMessage().startsWith("NotFound")) {
 +                            Messages.printNofFoundMessage("Schema", parameters[0]);
 +                        } else {
 +                            Messages.printMessage(ex.getMessage());
 +                        }
 +                    } catch (final IllegalArgumentException ex) {
 +                        Messages.printTypeNotValidMessage(
 +                                "schema", input.firstParameter(), fromEnumToArray(SchemaType.class));
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(readErrorMessage);
 +                }
 +                break;
 +            case DELETE:
 +                final String deleteErrorMessage = "schema --delete {SCHEMA-TYPE} {SCHEMA-KEY}\n"
 +                        + "   Schema type: PLAIN / DERIVED / VIRTUAL";
 +                if (parameters.length >= 2) {
 +                    parameters = Arrays.copyOfRange(parameters, 1, parameters.length);
 +                    try {
 +                        for (final String parameter : parameters) {
 +                            schemaService.delete(SchemaType.valueOf(input.firstParameter()), parameter);
 +                            Messages.printDeletedMessage("Schema", parameter);
 +                        }
 +                    } catch (final SyncopeClientException | WebServiceException ex) {
 +                        if (ex.getMessage().startsWith("NotFound")) {
 +                            Messages.printNofFoundMessage("Schema", parameters[0]);
 +                        } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
 +                            Messages.printMessage(
 +                                    "You cannot delete schema " + parameters[0]);
 +                        } else {
 +                            Messages.printMessage(ex.getMessage());
 +                        }
 +                    } catch (final IllegalArgumentException ex) {
 +                        Messages.printTypeNotValidMessage(
 +                                "schema", input.firstParameter(), fromEnumToArray(SchemaType.class));
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(deleteErrorMessage);
 +                }
 +                break;
 +            case HELP:
 +                System.out.println(HELP_MESSAGE);
 +                break;
 +            default:
 +                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
 +        }
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return HELP_MESSAGE;
 +    }
 +
 +    private enum Options {
 +
 +        HELP("--help"),
 +        LIST("--list"),
 +        LIST_ALL("--list-all"),
 +        LIST_PLAIN("--list-plain"),
 +        LIST_DERIVED("--list-derived"),
 +        LIST_VIRTUAL("--list-virtual"),
 +        READ("--read"),
 +        DELETE("--delete");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +
 +        public static List<String> toList() {
 +            final List<String> options = new ArrayList<>();
 +            for (final Options value : values()) {
 +                options.add(value.getOptionName());
 +            }
 +            return options;
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
----------------------------------------------------------------------
diff --cc client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
index 9dcb795,0000000..535d4af
mode 100644,000000..100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
@@@ -1,583 -1,0 +1,583 @@@
 +/*
 + * 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.cli.commands;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import java.util.Map;
 +import javax.xml.ws.WebServiceException;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.client.cli.Command;
 +import org.apache.syncope.client.cli.Input;
 +import org.apache.syncope.client.cli.SyncopeServices;
 +import org.apache.syncope.client.cli.messages.Messages;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.to.AbstractTaskTO;
 +import org.apache.syncope.common.lib.to.AnyTO;
 +import org.apache.syncope.common.lib.to.NotificationTaskTO;
 +import org.apache.syncope.common.lib.to.PropagationTaskTO;
 +import org.apache.syncope.common.lib.to.PushTaskTO;
 +import org.apache.syncope.common.lib.to.SchedTaskTO;
 +import org.apache.syncope.common.lib.to.SyncTaskTO;
 +import org.apache.syncope.common.lib.to.TaskExecTO;
 +import org.apache.syncope.common.lib.types.JobStatusType;
 +import org.apache.syncope.common.lib.types.TaskType;
 +import org.apache.syncope.common.rest.api.beans.TaskQuery;
 +import org.apache.syncope.common.rest.api.service.TaskService;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +
 +@Command(name = "task")
 +public class TaskCommand extends AbstractCommand {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
 +
 +    private static final String HELP_MESSAGE = "Usage: task [options]\n"
 +            + "  Options:\n"
 +            + "    --help \n"
 +            + "    --list-task \n"
 +            + "       Syntax: --list-task {TASK-TYPE} \n"
 +            + "          Task type: NOTIFICATION / PROPAGATION / PUSH / SCHEDULED / SYNCHRONIZATION\n"
 +            + "    --list-running-jobs \n"
 +            + "    --list-scheduled-jobs \n"
 +            + "    --read \n"
 +            + "       Syntax: --read {TASK-ID} {TASK-ID} [...]\n"
 +            + "    --read-execution \n"
 +            + "       Syntax: --read-execution {TASK-EXEC-ID} {TASK-EXEC-ID} [...]\n"
 +            + "    --delete \n"
 +            + "       Syntax: --delete {TASK-ID} {TASK-ID} [...]\n"
 +            + "    --delete-execution \n"
 +            + "       Syntax: --delete-execution {TASK-EXEC-ID} {TASK-EXEC-ID} [...]\n"
 +            + "    --execute \n"
 +            + "       Syntax: --execute {TASK-ID} {DRY-RUN}"
 +            + "          Dry run: true / false";
 +
 +    @Override
 +    public void execute(final Input input) {
 +        LOG.debug("Option: {}", input.getOption());
 +        LOG.debug("Parameters:");
 +        for (final String parameter : input.getParameters()) {
 +            LOG.debug("   > " + parameter);
 +        }
 +
 +        final String[] parameters = input.getParameters();
 +
 +        if (StringUtils.isBlank(input.getOption())) {
 +            input.setOption(Options.HELP.getOptionName());
 +        }
 +
 +        final TaskService taskService = SyncopeServices.get(TaskService.class);
 +        switch (Options.fromName(input.getOption())) {
 +            case LIST_TASK:
 +                final String listTaskErrorMessage = "task --list-task {TASK-TYPE}\n"
 +                        + "   Task type: NOTIFICATION / PROPAGATION / PUSH / SCHEDULED / SYNCHRONIZATION";
 +                if (parameters.length == 1) {
 +                    try {
 +                        final TaskType taskType = TaskType.valueOf(parameters[0]);
 +                        for (final AbstractTaskTO taskTO : taskService.list(taskType, new TaskQuery()).getResult()) {
 +                            switch (taskType) {
 +                                case NOTIFICATION:
 +                                    final NotificationTaskTO notificationTaskTO = (NotificationTaskTO) taskTO;
 +                                    System.out.println("");
 +                                    System.out.println(" - Notification task key: " + notificationTaskTO.getKey());
 +                                    System.out.println("     executed: " + notificationTaskTO.isExecuted());
 +                                    System.out.println("     sender: " + notificationTaskTO.getSender());
 +                                    System.out.println("     subjetc: " + notificationTaskTO.getSubject());
 +                                    System.out.println("     text body: " + notificationTaskTO.getTextBody());
 +                                    System.out.println("     html body: " + notificationTaskTO.getHtmlBody());
 +                                    System.out.println("     latest execution status: "
 +                                            + notificationTaskTO.getLatestExecStatus());
 +                                    System.out.println("     start date: " + notificationTaskTO.getStartDate());
 +                                    System.out.println("     end date: " + notificationTaskTO.getEndDate());
 +                                    System.out.println("     recipients: " + notificationTaskTO.getRecipients());
 +                                    System.out.println("     trace level: " + notificationTaskTO.getTraceLevel());
 +                                    for (final TaskExecTO taskExecTO : notificationTaskTO.getExecutions()) {
 +                                        printTaskExecTO(taskExecTO);
 +                                    }
 +                                    System.out.println("");
 +                                    break;
 +                                case PROPAGATION:
 +                                    final PropagationTaskTO propagationTaskTO = (PropagationTaskTO) taskTO;
 +                                    System.out.println("");
 +                                    System.out.println(" - Propagation task key: " + propagationTaskTO.getKey());
 +                                    System.out.println("     resource: " + propagationTaskTO.getResource());
 +                                    System.out.println("     any key: " + propagationTaskTO.getAnyKey());
 +                                    System.out.println("     any type kind: " + propagationTaskTO.getAnyTypeKind());
 +                                    System.out.println("     connector object key: "
 +                                            + propagationTaskTO.getConnObjectKey());
 +                                    System.out.println("     old connector object key: "
 +                                            + propagationTaskTO.getOldConnObjectKey());
 +                                    System.out.println("     latest execution status: "
 +                                            + propagationTaskTO.getLatestExecStatus());
 +                                    System.out.println("     class name: " + propagationTaskTO.getObjectClassName());
 +                                    System.out.println("     xml attribute: " + propagationTaskTO.getXmlAttributes());
 +                                    System.out.println("     start date: " + propagationTaskTO.getStartDate());
 +                                    System.out.println("     end date: " + propagationTaskTO.getEndDate());
 +                                    System.out.println("     operation: " + propagationTaskTO.getOperation());
 +                                    for (final TaskExecTO taskExecTO : propagationTaskTO.getExecutions()) {
 +                                        printTaskExecTO(taskExecTO);
 +                                    }
 +                                    System.out.println("");
 +                                    break;
 +                                case PUSH:
 +                                    final PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
 +                                    System.out.println("");
 +                                    System.out.println(" - Push task key: " + pushTaskTO.getKey());
 +                                    System.out.println("     name: " + pushTaskTO.getName());
 +                                    System.out.println("     resource: " + pushTaskTO.getResource());
 +                                    System.out.println("     cron expression: " + pushTaskTO.getCronExpression());
 +                                    System.out.println("     description: " + pushTaskTO.getDescription());
 +                                    System.out.println("     is perform create: " + pushTaskTO.isPerformCreate());
 +                                    System.out.println("     is perform delete: " + pushTaskTO.isPerformDelete());
 +                                    System.out.println("     is perform update: " + pushTaskTO.isPerformUpdate());
 +                                    System.out.println("     is sync status: " + pushTaskTO.isSyncStatus());
 +                                    System.out.println("     start date: " + pushTaskTO.getStartDate());
 +                                    System.out.println("     end date: " + pushTaskTO.getEndDate());
 +                                    System.out.println("     last execution: " + pushTaskTO.getLastExec());
 +                                    System.out.println("     next execution: " + pushTaskTO.getNextExec());
 +                                    System.out.println("     latest execution status: "
 +                                            + pushTaskTO.getLatestExecStatus());
 +                                    System.out.println("     filters: " + pushTaskTO.getFilters());
 +                                    System.out.println("     delegate class: " + pushTaskTO.getJobDelegateClassName());
 +                                    System.out.println("     action class: " + pushTaskTO.getActionsClassNames());
 +                                    System.out.println("     matching rule: " + pushTaskTO.getMatchingRule());
 +                                    System.out.println("     not matching rule: " + pushTaskTO.getUnmatchingRule());
 +                                    for (final TaskExecTO taskExecTO : pushTaskTO.getExecutions()) {
 +                                        printTaskExecTO(taskExecTO);
 +                                    }
 +                                    System.out.println("");
 +                                    break;
 +                                case SCHEDULED:
 +                                    final SchedTaskTO schedTaskTO = (SchedTaskTO) taskTO;
 +                                    System.out.println("");
 +                                    System.out.println(" - Scheduled task key: " + schedTaskTO.getKey());
 +                                    System.out.println("     name: " + schedTaskTO.getName());
 +                                    System.out.println("     cron expression: " + schedTaskTO.getCronExpression());
 +                                    System.out.println("     description: " + schedTaskTO.getDescription());
 +                                    System.out.println("     start date: " + schedTaskTO.getStartDate());
 +                                    System.out.println("     end date: " + schedTaskTO.getEndDate());
 +                                    System.out.println("     last execution: " + schedTaskTO.getLastExec());
 +                                    System.out.println("     next execution: " + schedTaskTO.getNextExec());
 +                                    System.out.println("     latest execution status: "
 +                                            + schedTaskTO.getLatestExecStatus());
 +                                    System.out.println("     job delegate class: "
 +                                            + schedTaskTO.getJobDelegateClassName());
 +                                    for (final TaskExecTO taskExecTO : schedTaskTO.getExecutions()) {
 +                                        printTaskExecTO(taskExecTO);
 +                                    }
 +                                    System.out.println("");
 +                                    break;
 +                                case SYNCHRONIZATION:
 +                                    final SyncTaskTO syncTaskTO = (SyncTaskTO) taskTO;
 +                                    System.out.println("");
 +                                    System.out.println(" - Sync task key: " + syncTaskTO.getKey());
 +                                    System.out.println("     name: " + syncTaskTO.getName());
 +                                    System.out.println("     resource: " + syncTaskTO.getResource());
 +                                    System.out.println("     realm destination: " + syncTaskTO.getDestinationRealm());
 +                                    System.out.println("     cron expression: " + syncTaskTO.getCronExpression());
 +                                    System.out.println("     description: " + syncTaskTO.getDescription());
 +                                    System.out.println("     is full reconciliation: "
 +                                            + syncTaskTO.isFullReconciliation());
 +                                    System.out.println("     is perform create: " + syncTaskTO.isPerformCreate());
 +                                    System.out.println("     is perform delete: " + syncTaskTO.isPerformDelete());
 +                                    System.out.println("     is perform update: " + syncTaskTO.isPerformUpdate());
 +                                    System.out.println("     is sync status: " + syncTaskTO.isSyncStatus());
 +                                    System.out.println("     templates:");
 +                                    for (Map.Entry<String, AnyTO> entrySet : syncTaskTO.getTemplates().entrySet()) {
 +                                        final String key = entrySet.getKey();
 +                                        final AnyTO value = entrySet.getValue();
 +                                        System.out.println("        " + key + " key: " + value.getKey()
 +                                                + " of realm" + value.getRealm()
 +                                                + " on resource " + value.getResources());
 +
 +                                    }
 +                                    System.out.println("     start date: " + syncTaskTO.getStartDate());
 +                                    System.out.println("     end date: " + syncTaskTO.getEndDate());
 +                                    System.out.println("     next execution: " + syncTaskTO.getNextExec());
 +                                    System.out.println("     last execution: " + syncTaskTO.getLastExec());
 +                                    System.out.println("     latest execution status: "
 +                                            + syncTaskTO.getLatestExecStatus());
 +                                    System.out.println("     job delegate class: "
 +                                            + syncTaskTO.getJobDelegateClassName());
 +                                    System.out.println("     action class name: " + syncTaskTO.getActionsClassNames());
 +                                    System.out.println("     matching rule: " + syncTaskTO.getMatchingRule());
 +                                    System.out.println("     unmatching rule: " + syncTaskTO.getUnmatchingRule());
 +                                    for (final TaskExecTO taskExecTO : syncTaskTO.getExecutions()) {
 +                                        printTaskExecTO(taskExecTO);
 +                                    }
 +                                    System.out.println("");
 +                                    break;
 +                                default:
 +                                    break;
 +                            }
 +                        }
 +                    } catch (final SyncopeClientException ex) {
 +                        Messages.printMessage(ex.getMessage());
 +                    } catch (final IllegalArgumentException ex) {
 +                        Messages.printTypeNotValidMessage("task", parameters[0], fromEnumToArray(TaskType.class));
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(listTaskErrorMessage);
 +                }
 +                break;
 +            case LIST_RUNNING_JOBS:
 +                try {
 +                    for (final TaskExecTO taskExecTO : taskService.listJobs(JobStatusType.RUNNING)) {
 +                        printTaskExecTO(taskExecTO);
 +                    }
 +                } catch (final SyncopeClientException ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                }
 +                break;
 +            case LIST_SCHEDULED_JOBS:
 +                try {
 +                    for (final TaskExecTO taskExecTO : taskService.listJobs(JobStatusType.SCHEDULED)) {
 +                        printTaskExecTO(taskExecTO);
 +                    }
 +                } catch (final SyncopeClientException ex) {
 +                    Messages.printMessage(ex.getMessage());
 +                }
 +                break;
 +            case READ:
 +                final String readErrorMessage = "task --read {TASK-ID} {TASK-ID} [...]";
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            final AbstractTaskTO taskTO = taskService.read(Long.valueOf(parameter));
 +                            if (taskTO instanceof NotificationTaskTO) {
 +                                final NotificationTaskTO notificationTaskTO = (NotificationTaskTO) taskTO;
 +                                System.out.println("");
 +                                System.out.println(" - Notification task key: " + notificationTaskTO.getKey());
 +                                System.out.println("     executed: " + notificationTaskTO.isExecuted());
 +                                System.out.println("     sender: " + notificationTaskTO.getSender());
 +                                System.out.println("     subjetc: " + notificationTaskTO.getSubject());
 +                                System.out.println("     text body: " + notificationTaskTO.getTextBody());
 +                                System.out.println("     html body: " + notificationTaskTO.getHtmlBody());
 +                                System.out.println("     latest execution status: "
 +                                        + notificationTaskTO.getLatestExecStatus());
 +                                System.out.println("     start date: " + notificationTaskTO.getStartDate());
 +                                System.out.println("     end date: " + notificationTaskTO.getEndDate());
 +                                System.out.println("     recipients: " + notificationTaskTO.getRecipients());
 +                                System.out.println("     trace level: " + notificationTaskTO.getTraceLevel());
 +                                for (final TaskExecTO taskExecTO : notificationTaskTO.getExecutions()) {
 +                                    printTaskExecTO(taskExecTO);
 +                                }
 +                                System.out.println("");
 +                            } else if (taskTO instanceof PropagationTaskTO) {
 +                                final PropagationTaskTO propagationTaskTO = (PropagationTaskTO) taskTO;
 +                                System.out.println("");
 +                                System.out.println(" - Propagation task key: " + propagationTaskTO.getKey());
 +                                System.out.println("     resource: " + propagationTaskTO.getResource());
 +                                System.out.println("     any key: " + propagationTaskTO.getAnyKey());
 +                                System.out.println("     any type kind: " + propagationTaskTO.getAnyTypeKind());
 +                                System.out.println("     connector object key: "
 +                                        + propagationTaskTO.getConnObjectKey());
 +                                System.out.println("     old connector object key: "
 +                                        + propagationTaskTO.getOldConnObjectKey());
 +                                System.out.println("     latest execution status: "
 +                                        + propagationTaskTO.getLatestExecStatus());
 +                                System.out.println("     class name: " + propagationTaskTO.getObjectClassName());
 +                                System.out.println("     xml attribute: " + propagationTaskTO.getXmlAttributes());
 +                                System.out.println("     start date: " + propagationTaskTO.getStartDate());
 +                                System.out.println("     end date: " + propagationTaskTO.getEndDate());
 +                                System.out.println("     operation: " + propagationTaskTO.getOperation());
 +                                for (final TaskExecTO taskExecTO : propagationTaskTO.getExecutions()) {
 +                                    printTaskExecTO(taskExecTO);
 +                                }
 +                                System.out.println("");
 +                            } else if (taskTO instanceof PushTaskTO) {
 +                                final PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
 +                                System.out.println("");
 +                                System.out.println(" - Push task key: " + pushTaskTO.getKey());
 +                                System.out.println("     name: " + pushTaskTO.getName());
 +                                System.out.println("     resource: " + pushTaskTO.getResource());
 +                                System.out.println("     cron expression: " + pushTaskTO.getCronExpression());
 +                                System.out.println("     description: " + pushTaskTO.getDescription());
 +                                System.out.println("     is perform create: " + pushTaskTO.isPerformCreate());
 +                                System.out.println("     is perform delete: " + pushTaskTO.isPerformDelete());
 +                                System.out.println("     is perform update: " + pushTaskTO.isPerformUpdate());
 +                                System.out.println("     is sync status: " + pushTaskTO.isSyncStatus());
 +                                System.out.println("     start date: " + pushTaskTO.getStartDate());
 +                                System.out.println("     end date: " + pushTaskTO.getEndDate());
 +                                System.out.println("     last execution: " + pushTaskTO.getLastExec());
 +                                System.out.println("     next execution: " + pushTaskTO.getNextExec());
 +                                System.out.println("     latest execution status: "
 +                                        + pushTaskTO.getLatestExecStatus());
 +                                System.out.println("     filters: " + pushTaskTO.getFilters());
 +                                System.out.println("     delegate class: " + pushTaskTO.getJobDelegateClassName());
 +                                System.out.println("     action class: " + pushTaskTO.getActionsClassNames());
 +                                System.out.println("     matching rule: " + pushTaskTO.getMatchingRule());
 +                                System.out.println("     not matching rule: " + pushTaskTO.getUnmatchingRule());
 +                                for (final TaskExecTO taskExecTO : pushTaskTO.getExecutions()) {
 +                                    printTaskExecTO(taskExecTO);
 +                                }
 +                                System.out.println("");
 +                            } else if (taskTO instanceof SchedTaskTO) {
 +                                final SchedTaskTO schedTaskTO = (SchedTaskTO) taskTO;
 +                                System.out.println("");
 +                                System.out.println(" - Scheduled task key: " + schedTaskTO.getKey());
 +                                System.out.println("     name: " + schedTaskTO.getName());
 +                                System.out.println("     cron expression: " + schedTaskTO.getCronExpression());
 +                                System.out.println("     description: " + schedTaskTO.getDescription());
 +                                System.out.println("     start date: " + schedTaskTO.getStartDate());
 +                                System.out.println("     end date: " + schedTaskTO.getEndDate());
 +                                System.out.println("     last execution: " + schedTaskTO.getLastExec());
 +                                System.out.println("     next execution: " + schedTaskTO.getNextExec());
 +                                System.out.println("     latest execution status: "
 +                                        + schedTaskTO.getLatestExecStatus());
 +                                System.out.println("     job delegate class: "
 +                                        + schedTaskTO.getJobDelegateClassName());
 +                                for (final TaskExecTO taskExecTO : schedTaskTO.getExecutions()) {
 +                                    printTaskExecTO(taskExecTO);
 +                                }
 +                                System.out.println("");
 +                            } else if (taskTO instanceof SyncTaskTO) {
 +                                final SyncTaskTO syncTaskTO = (SyncTaskTO) taskTO;
 +                                System.out.println("");
 +                                System.out.println(" - Sync task key: " + syncTaskTO.getKey());
 +                                System.out.println("     name: " + syncTaskTO.getName());
 +                                System.out.println("     resource: " + syncTaskTO.getResource());
 +                                System.out.println("     realm destination: " + syncTaskTO.getDestinationRealm());
 +                                System.out.println("     cron expression: " + syncTaskTO.getCronExpression());
 +                                System.out.println("     description: " + syncTaskTO.getDescription());
 +                                System.out.println("     is full reconciliation: "
 +                                        + syncTaskTO.isFullReconciliation());
 +                                System.out.println("     is perform create: " + syncTaskTO.isPerformCreate());
 +                                System.out.println("     is perform delete: " + syncTaskTO.isPerformDelete());
 +                                System.out.println("     is perform update: " + syncTaskTO.isPerformUpdate());
 +                                System.out.println("     is sync status: " + syncTaskTO.isSyncStatus());
 +                                System.out.println("     templates:");
 +                                for (Map.Entry<String, AnyTO> entrySet : syncTaskTO.getTemplates().entrySet()) {
 +                                    final String key = entrySet.getKey();
 +                                    final AnyTO value = entrySet.getValue();
 +                                    System.out.println("        " + key + "key : " + value.getKey()
 +                                            + " of realm" + value.getRealm()
 +                                            + " on resource " + value.getResources());
 +
 +                                }
 +                                System.out.println("     start date: " + syncTaskTO.getStartDate());
 +                                System.out.println("     end date: " + syncTaskTO.getEndDate());
 +                                System.out.println("     next execution: " + syncTaskTO.getNextExec());
 +                                System.out.println("     last execution: " + syncTaskTO.getLastExec());
 +                                System.out.println("     latest execution status: "
 +                                        + syncTaskTO.getLatestExecStatus());
 +                                System.out.println("     job delegate class: "
 +                                        + syncTaskTO.getJobDelegateClassName());
 +                                System.out.println("     action class name: " + syncTaskTO.getActionsClassNames());
 +                                System.out.println("     matching rule: " + syncTaskTO.getMatchingRule());
 +                                System.out.println("     unmatching rule: " + syncTaskTO.getUnmatchingRule());
 +                                for (final TaskExecTO taskExecTO : syncTaskTO.getExecutions()) {
 +                                    printTaskExecTO(taskExecTO);
 +                                }
 +                                System.out.println("");
 +                            }
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("task", parameter);
 +                        } catch (final SyncopeClientException | WebServiceException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Task", parameter);
 +                            } else {
 +                                Messages.printMessage("Error: " + ex.getMessage());
 +                            }
 +                            break;
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(readErrorMessage);
 +                }
 +                break;
 +            case READ_EXECUTION:
 +                final String readExecutionErrorMessage = "task --read-execution {TASK-ID} {TASK-ID} [...]";
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            final TaskExecTO taskExecTO = taskService.readExecution(Long.valueOf(parameter));
 +                            printTaskExecTO(taskExecTO);
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("task execution", parameter);
 +                        } catch (final SyncopeClientException | WebServiceException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Task execution", parameter);
 +                            } else {
 +                                Messages.printMessage("Error: " + ex.getMessage());
 +                            }
 +                            break;
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(readExecutionErrorMessage);
 +                }
 +                break;
 +            case DELETE:
 +                final String deleteErrorMessage = "task --delete {TASK-ID} {TASK-ID} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            taskService.delete(Long.valueOf(parameter));
 +                            Messages.printDeletedMessage("Task", parameter);
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Task", parameter);
 +                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
 +                                Messages.printMessage("You cannot delete task " + parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("task", parameter);
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(deleteErrorMessage);
 +                }
 +                break;
 +            case DELETE_EXECUTION:
 +                final String deleteExecutionErrorMessage = "task --delete-execution "
 +                        + "{TASK-EXEC-ID} {TASK-EXEC-ID} [...]";
 +
 +                if (parameters.length >= 1) {
 +                    for (final String parameter : parameters) {
 +                        try {
 +                            taskService.deleteExecution(Long.valueOf(parameter));
 +                            Messages.printDeletedMessage("Task execution", parameter);
 +                        } catch (final WebServiceException | SyncopeClientException ex) {
 +                            if (ex.getMessage().startsWith("NotFound")) {
 +                                Messages.printNofFoundMessage("Task execution", parameter);
 +                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
 +                                Messages.printMessage("You cannot delete task execution" + parameter);
 +                            } else {
 +                                Messages.printMessage(ex.getMessage());
 +                            }
 +                        } catch (final NumberFormatException ex) {
 +                            Messages.printIdNotNumberDeletedMessage("task execution", parameter);
 +                        }
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(deleteExecutionErrorMessage);
 +                }
 +                break;
 +            case EXECUTE:
 +                final String executeErrorMessage = "task --execute {TASK-ID} {DRY-RUN}\n"
 +                        + "          Dry run: true / false";
 +
 +                if (parameters.length == 2) {
 +
 +                    try {
 +                        final Long taskIdToExecute = Long.valueOf(parameters[0]);
 +                        boolean dryRun;
 +                        if ("false".equalsIgnoreCase(parameters[1])) {
 +                            dryRun = false;
 +                        } else if ("true".equalsIgnoreCase(parameters[1])) {
 +                            dryRun = true;
 +                        } else {
 +                            Messages.printNotBooleanDeletedMessage("dry run", parameters[1]);
 +                            break;
 +                        }
 +                        final TaskExecTO taskExecTO = taskService.execute(taskIdToExecute, dryRun);
 +                        printTaskExecTO(taskExecTO);
 +                    } catch (final WebServiceException | SyncopeClientException ex) {
 +                        System.out.println("Error:");
 +                        if (ex.getMessage().startsWith("NotFound")) {
 +                            Messages.printNofFoundMessage("Task", parameters[0]);
 +                        } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
 +                            Messages.printMessage("You cannot delete task " + parameters[0]);
 +                        } else {
 +                            Messages.printMessage(ex.getMessage());
 +                        }
 +                    } catch (final NumberFormatException ex) {
 +                        Messages.printIdNotNumberDeletedMessage("task", parameters[0]);
 +                    }
 +                } else {
 +                    Messages.printCommandOptionMessage(executeErrorMessage);
 +                }
 +                break;
 +            case HELP:
 +                System.out.println(HELP_MESSAGE);
 +                break;
 +            default:
 +                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
 +        }
 +
 +    }
 +
 +    private void printTaskExecTO(final TaskExecTO taskExecTO) {
 +        System.out.println("     EXECUTIONS: ");
 +        System.out.println("     - task execution key: " + taskExecTO.getKey());
 +        System.out.println("       task: " + taskExecTO.getTask());
 +        System.out.println("       message: ");
 +        System.out.println("       ###############     <BEGIN MESSAGE>     ###############");
 +        System.out.println("       message: " + taskExecTO.getMessage());
 +        System.out.println("       ###############     <END   MESSAGE>     ###############");
 +        System.out.println("       status: " + taskExecTO.getStatus());
 +        System.out.println("       start date: " + taskExecTO.getStartDate());
 +        System.out.println("       end date: " + taskExecTO.getEndDate());
 +        System.out.println("");
 +    }
 +
 +    @Override
 +    public String getHelpMessage() {
 +        return HELP_MESSAGE;
 +    }
 +
 +    private enum Options {
 +
 +        HELP("--help"),
 +        LIST_TASK("--list-task"),
 +        LIST_RUNNING_JOBS("--list-running-jobs"),
 +        LIST_SCHEDULED_JOBS("--list-scheduled-jobs"),
 +        READ("--read"),
 +        READ_EXECUTION("--read-execution"),
 +        DELETE("--delete"),
 +        DELETE_EXECUTION("--delete-execution"),
 +        EXECUTE("--execute");
 +
 +        private final String optionName;
 +
-         private Options(final String optionName) {
++        Options(final String optionName) {
 +            this.optionName = optionName;
 +        }
 +
 +        public String getOptionName() {
 +            return optionName;
 +        }
 +
 +        public boolean equalsOptionName(final String otherName) {
 +            return (otherName == null) ? false : optionName.equals(otherName);
 +        }
 +
 +        public static Options fromName(final String name) {
 +            Options optionToReturn = HELP;
 +            for (final Options option : Options.values()) {
 +                if (option.equalsOptionName(name)) {
 +                    optionToReturn = option;
 +                }
 +            }
 +            return optionToReturn;
 +        }
 +
 +        public static List<String> toList() {
 +            final List<String> options = new ArrayList<>();
 +            for (final Options value : values()) {
 +                options.add(value.getOptionName());
 +            }
 +            return options;
 +        }
 +    }
 +}


[41/54] [abbrv] syncope git commit: [SYNCOPE-709] Refactoring completed

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
index 0d15ffd..77efd28 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
@@ -29,7 +29,6 @@ import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.StringPatchItem;
 import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.AttrTO;
@@ -40,9 +39,7 @@ import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
 import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
-import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.WorkflowResult;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
@@ -51,11 +48,15 @@ import org.apache.syncope.core.misc.MappingUtils;
 import org.apache.syncope.core.misc.jexl.JexlUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.provisioning.api.VirAttrHandler;
+import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeBuilder;
 import org.identityconnectors.framework.common.objects.AttributeUtil;
@@ -73,6 +74,9 @@ public class PropagationManagerImpl implements PropagationManager {
     protected static final Logger LOG = LoggerFactory.getLogger(PropagationManager.class);
 
     @Autowired
+    protected VirSchemaDAO virSchemaDAO;
+
+    @Autowired
     protected AnyObjectDAO anyObjectDAO;
 
     /**
@@ -103,13 +107,10 @@ public class PropagationManagerImpl implements PropagationManager {
     protected ConnObjectUtils connObjectUtils;
 
     @Autowired
-    protected VirAttrHandler virAttrHandler;
-
-    @Autowired
     protected MappingUtils mappingUtils;
 
-    protected Any<?, ?, ?> find(final AnyTypeKind kind, final Long key) {
-        AnyDAO<? extends Any<?, ?, ?>> dao;
+    protected Any<?, ?> find(final AnyTypeKind kind, final Long key) {
+        AnyDAO<? extends Any<?, ?>> dao;
         switch (kind) {
             case ANY_OBJECT:
                 dao = anyObjectDAO;
@@ -135,12 +136,7 @@ public class PropagationManagerImpl implements PropagationManager {
             final Collection<AttrTO> vAttrs,
             final Collection<String> noPropResourceNames) {
 
-        Any<?, ?, ?> any = find(kind, key);
-        if (vAttrs != null && !vAttrs.isEmpty()) {
-            virAttrHandler.createVirtual(any, vAttrs);
-        }
-
-        return getCreateTasks(any, null, null, propByRes, noPropResourceNames);
+        return getCreateTasks(find(kind, key), null, null, propByRes, vAttrs, noPropResourceNames);
     }
 
     @Override
@@ -152,19 +148,15 @@ public class PropagationManagerImpl implements PropagationManager {
             final Collection<AttrTO> vAttrs,
             final Collection<String> noPropResourceNames) {
 
-        User user = userDAO.authFind(key);
-        if (vAttrs != null && !vAttrs.isEmpty()) {
-            virAttrHandler.createVirtual(user, vAttrs);
-        }
-
-        return getCreateTasks(user, password, enable, propByRes, noPropResourceNames);
+        return getCreateTasks(userDAO.authFind(key), password, enable, propByRes, vAttrs, noPropResourceNames);
     }
 
     protected List<PropagationTask> getCreateTasks(
-            final Any<?, ?, ?> any,
+            final Any<?, ?> any,
             final String password,
             final Boolean enable,
             final PropagationByResource propByRes,
+            final Collection<AttrTO> vAttrs,
             final Collection<String> noPropResourceNames) {
 
         if (propByRes == null || propByRes.isEmpty()) {
@@ -175,7 +167,7 @@ public class PropagationManagerImpl implements PropagationManager {
             propByRes.get(ResourceOperation.CREATE).removeAll(noPropResourceNames);
         }
 
-        return createTasks(any, password, true, null, enable, false, propByRes);
+        return createTasks(any, password, true, enable, false, propByRes, vAttrs);
     }
 
     @Override
@@ -185,7 +177,7 @@ public class PropagationManagerImpl implements PropagationManager {
             final boolean changePwd,
             final Boolean enable,
             final PropagationByResource propByRes,
-            final Collection<AttrPatch> vAttrs,
+            final Collection<AttrTO> vAttrs,
             final Collection<String> noPropResourceNames) {
 
         return getUpdateTasks(find(kind, key), null, changePwd, enable, propByRes, vAttrs, noPropResourceNames);
@@ -257,31 +249,19 @@ public class PropagationManagerImpl implements PropagationManager {
     }
 
     protected List<PropagationTask> getUpdateTasks(
-            final Any<?, ?, ?> any,
+            final Any<?, ?> any,
             final String password,
             final boolean changePwd,
             final Boolean enable,
             final PropagationByResource propByRes,
-            final Collection<AttrPatch> vAttrs,
+            final Collection<AttrTO> vAttrs,
             final Collection<String> noPropResourceNames) {
 
-        PropagationByResource localPropByRes = virAttrHandler.updateVirtual(
-                any,
-                vAttrs == null ? Collections.<AttrPatch>emptySet() : vAttrs);
-        localPropByRes.merge(propByRes);
         if (noPropResourceNames != null) {
-            localPropByRes.removeAll(noPropResourceNames);
-        }
-
-        Map<String, AttrPatch> vAttrsMap = null;
-        if (vAttrs != null) {
-            vAttrsMap = new HashMap<>();
-            for (AttrPatch attrPatch : vAttrs) {
-                vAttrsMap.put(attrPatch.getAttrTO().getSchema(), attrPatch);
-            }
+            propByRes.removeAll(noPropResourceNames);
         }
 
-        return createTasks(any, password, changePwd, vAttrsMap, enable, false, localPropByRes);
+        return createTasks(any, password, changePwd, enable, false, propByRes, vAttrs);
     }
 
     @Override
@@ -291,7 +271,7 @@ public class PropagationManagerImpl implements PropagationManager {
             final PropagationByResource propByRes,
             final Collection<String> noPropResourceNames) {
 
-        Any<?, ?, ?> any = find(kind, key);
+        Any<?, ?> any = find(kind, key);
 
         PropagationByResource localPropByRes = new PropagationByResource();
 
@@ -309,109 +289,143 @@ public class PropagationManagerImpl implements PropagationManager {
     }
 
     protected List<PropagationTask> getDeleteTasks(
-            final Any<?, ?, ?> any,
+            final Any<?, ?> any,
             final PropagationByResource propByRes,
             final Collection<String> noPropResourceNames) {
 
-        return createTasks(any, null, false, null, false, true, propByRes);
+        return createTasks(any, null, false, false, true, propByRes, null);
     }
 
     /**
      * Create propagation tasks.
      *
-     * @param any user / group to be provisioned
-     * @param password cleartext password to be provisioned
+     * @param any to be provisioned
+     * @param password clear text password to be provisioned
      * @param changePwd whether password should be included for propagation attributes or not
-     * @param vAttrs virtual attributes to be maaged
      * @param enable whether user must be enabled or not
-     * @param deleteOnResource whether user / group must be deleted anyway from external resource or not
+     * @param deleteOnResource whether any must be deleted anyway from external resource or not
      * @param propByRes operation to be performed per resource
+     * @param vAttrs virtual attributes to be set
      * @return list of propagation tasks created
      */
-    protected List<PropagationTask> createTasks(final Any<?, ?, ?> any,
+    protected List<PropagationTask> createTasks(final Any<?, ?> any,
             final String password, final boolean changePwd,
-            final Map<String, AttrPatch> vAttrs,
-            final Boolean enable, final boolean deleteOnResource, final PropagationByResource propByRes) {
+            final Boolean enable, final boolean deleteOnResource, final PropagationByResource propByRes,
+            final Collection<AttrTO> vAttrs) {
 
-        LOG.debug("Provisioning any {}:\n{}", any, propByRes);
+        LOG.debug("Provisioning {}:\n{}", any, propByRes);
 
-        if (!propByRes.get(ResourceOperation.CREATE).isEmpty() && vAttrs != null) {
-            virAttrHandler.retrieveVirAttrValues(any);
+        // Avoid duplicates - see javadoc
+        propByRes.purge();
+        LOG.debug("After purge {}:\n{}", any, propByRes);
+
+        // Virtual attributes
+        Set<String> virtualResources = new HashSet<>();
+        virtualResources.addAll(propByRes.get(ResourceOperation.CREATE));
+        virtualResources.addAll(propByRes.get(ResourceOperation.UPDATE));
+        if (any instanceof User) {
+            virtualResources.addAll(userDAO.findAllResourceNames((User) any));
+        } else if (any instanceof AnyObject) {
+            virtualResources.addAll(anyObjectDAO.findAllResourceNames((AnyObject) any));
+        } else {
+            virtualResources.addAll(((Group) any).getResourceNames());
+        }
 
-            // update vAttrsToBeUpdated as well
-            for (VirAttr<?> virAttr : any.getVirAttrs()) {
-                String schema = virAttr.getSchema().getKey();
+        Map<String, Set<Attribute>> vAttrMap = new HashMap<>();
+        for (AttrTO vAttr : CollectionUtils.emptyIfNull(vAttrs)) {
+            VirSchema schema = virSchemaDAO.find(vAttr.getSchema());
+            if (schema == null) {
+                LOG.warn("Ignoring invalid {} {}", VirSchema.class.getSimpleName(), vAttr.getSchema());
+            } else if (schema.isReadonly()) {
+                LOG.warn("Ignoring read-only {} {}", VirSchema.class.getSimpleName(), vAttr.getSchema());
+            } else {
+                if (any.getAllowedVirSchemas().contains(schema)
+                        && virtualResources.contains(schema.getProvision().getResource().getKey())) {
+
+                    Set<Attribute> values = vAttrMap.get(schema.getProvision().getResource().getKey());
+                    if (values == null) {
+                        values = new HashSet<>();
+                        vAttrMap.put(schema.getProvision().getResource().getKey(), values);
+                    }
+                    values.add(AttributeBuilder.build(schema.getExtAttrName(), vAttr.getValues()));
 
-                vAttrs.put(schema, new AttrPatch.Builder().
-                        attrTO(new AttrTO.Builder().schema(schema).values(virAttr.getValues()).build()).
-                        build());
+                    propByRes.add(ResourceOperation.UPDATE, schema.getProvision().getResource().getKey());
+                } else {
+                    LOG.warn("{} not owned by or {} not allowed for {}",
+                            schema.getProvision().getResource(), schema, any);
+                }
             }
         }
-
-        // Avoid duplicates - see javadoc
-        propByRes.purge();
-        LOG.debug("After purge: {}", propByRes);
+        LOG.debug("With virtual attributes {}:\n{}\n{}", any, propByRes, vAttrMap);
 
         List<PropagationTask> tasks = new ArrayList<>();
 
-        for (ResourceOperation operation : ResourceOperation.values()) {
-            for (String resourceName : propByRes.get(operation)) {
-                ExternalResource resource = resourceDAO.find(resourceName);
-                Provision provision = resource == null ? null : resource.getProvision(any.getType());
-                if (resource == null) {
-                    LOG.error("Invalid resource name specified: {}, ignoring...", resourceName);
-                } else if (provision == null) {
-                    LOG.error("No provision specified on resource {} for type {}, ignoring...",
-                            resource, any.getType());
-                } else if (MappingUtils.getPropagationMappingItems(provision).isEmpty()) {
-                    LOG.warn("Requesting propagation for {} but no propagation mapping provided for {}",
-                            any.getType(), resource);
-                } else {
-                    PropagationTask task = entityFactory.newEntity(PropagationTask.class);
-                    task.setResource(resource);
-                    task.setObjectClassName(
-                            resource.getProvision(any.getType()).getObjectClass().getObjectClassValue());
-                    task.setAnyTypeKind(any.getType().getKind());
-                    if (!deleteOnResource) {
-                        task.setAnyKey(any.getKey());
-                    }
-                    task.setOperation(operation);
-                    task.setOldConnObjectKey(propByRes.getOldConnObjectKey(resource.getKey()));
-
-                    Pair<String, Set<Attribute>> preparedAttrs = mappingUtils.prepareAttrs(
-                            any, password, changePwd, vAttrs, enable, provision);
-                    task.setConnObjectKey(preparedAttrs.getKey());
-
-                    // Check if any of mandatory attributes (in the mapping) is missing or not received any value: 
-                    // if so, add special attributes that will be evaluated by PropagationTaskExecutor
-                    List<String> mandatoryMissing = new ArrayList<>();
-                    List<String> mandatoryNullOrEmpty = new ArrayList<>();
-                    for (MappingItem item : MappingUtils.getPropagationMappingItems(provision)) {
-                        if (!item.isConnObjectKey()
-                                && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) {
-
-                            Attribute attr = AttributeUtil.find(item.getExtAttrName(), preparedAttrs.getValue());
-                            if (attr == null) {
-                                mandatoryMissing.add(item.getExtAttrName());
-                            } else if (attr.getValue() == null || attr.getValue().isEmpty()) {
-                                mandatoryNullOrEmpty.add(item.getExtAttrName());
-                            }
+        for (Map.Entry<String, ResourceOperation> entry : propByRes.asMap().entrySet()) {
+            ExternalResource resource = resourceDAO.find(entry.getKey());
+            Provision provision = resource == null ? null : resource.getProvision(any.getType());
+            List<MappingItem> mappingItems = provision == null
+                    ? Collections.<MappingItem>emptyList()
+                    : MappingUtils.getPropagationMappingItems(provision);
+
+            if (resource == null) {
+                LOG.error("Invalid resource name specified: {}, ignoring...", entry.getKey());
+            } else if (provision == null) {
+                LOG.error("No provision specified on resource {} for type {}, ignoring...",
+                        resource, any.getType());
+            } else if (mappingItems.isEmpty()) {
+                LOG.warn("Requesting propagation for {} but no propagation mapping provided for {}",
+                        any.getType(), resource);
+            } else {
+                PropagationTask task = entityFactory.newEntity(PropagationTask.class);
+                task.setResource(resource);
+                task.setObjectClassName(
+                        resource.getProvision(any.getType()).getObjectClass().getObjectClassValue());
+                task.setAnyTypeKind(any.getType().getKind());
+                task.setAnyType(any.getType().getKey());
+                if (!deleteOnResource) {
+                    task.setAnyKey(any.getKey());
+                }
+                task.setOperation(entry.getValue());
+                task.setOldConnObjectKey(propByRes.getOldConnObjectKey(resource.getKey()));
+
+                Pair<String, Set<Attribute>> preparedAttrs =
+                        mappingUtils.prepareAttrs(any, password, changePwd, enable, provision);
+                task.setConnObjectKey(preparedAttrs.getKey());
+
+                // Check if any of mandatory attributes (in the mapping) is missing or not received any value: 
+                // if so, add special attributes that will be evaluated by PropagationTaskExecutor
+                List<String> mandatoryMissing = new ArrayList<>();
+                List<String> mandatoryNullOrEmpty = new ArrayList<>();
+                for (MappingItem item : mappingItems) {
+                    if (!item.isConnObjectKey()
+                            && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) {
+
+                        Attribute attr = AttributeUtil.find(item.getExtAttrName(), preparedAttrs.getValue());
+                        if (attr == null) {
+                            mandatoryMissing.add(item.getExtAttrName());
+                        } else if (attr.getValue() == null || attr.getValue().isEmpty()) {
+                            mandatoryNullOrEmpty.add(item.getExtAttrName());
                         }
                     }
-                    if (!mandatoryMissing.isEmpty()) {
-                        preparedAttrs.getValue().add(AttributeBuilder.build(
-                                PropagationTaskExecutor.MANDATORY_MISSING_ATTR_NAME, mandatoryMissing));
-                    }
-                    if (!mandatoryNullOrEmpty.isEmpty()) {
-                        preparedAttrs.getValue().add(AttributeBuilder.build(
-                                PropagationTaskExecutor.MANDATORY_NULL_OR_EMPTY_ATTR_NAME, mandatoryNullOrEmpty));
-                    }
-
-                    task.setAttributes(preparedAttrs.getValue());
-                    tasks.add(task);
+                }
+                if (!mandatoryMissing.isEmpty()) {
+                    preparedAttrs.getValue().add(AttributeBuilder.build(
+                            PropagationTaskExecutor.MANDATORY_MISSING_ATTR_NAME, mandatoryMissing));
+                }
+                if (!mandatoryNullOrEmpty.isEmpty()) {
+                    preparedAttrs.getValue().add(AttributeBuilder.build(
+                            PropagationTaskExecutor.MANDATORY_NULL_OR_EMPTY_ATTR_NAME, mandatoryNullOrEmpty));
+                }
 
-                    LOG.debug("PropagationTask created: {}", task);
+                if (vAttrMap.containsKey(resource.getKey())) {
+                    preparedAttrs.getValue().addAll(vAttrMap.get(resource.getKey()));
                 }
+
+                task.setAttributes(preparedAttrs.getValue());
+
+                tasks.add(task);
+
+                LOG.debug("PropagationTask created: {}", task);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
index 94936eb..dcce5e5 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
@@ -20,25 +20,19 @@ package org.apache.syncope.core.provisioning.java.sync;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
+import org.apache.commons.collections4.IteratorUtils;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.syncope.common.lib.patch.AnyPatch;
-import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.StringPatchItem;
 import org.apache.syncope.common.lib.to.AnyTO;
-import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.types.AuditElements;
 import org.apache.syncope.common.lib.types.AuditElements.Result;
-import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.MatchingRule;
 import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.common.lib.types.UnmatchingRule;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
 import org.apache.syncope.core.persistence.api.entity.task.PushTask;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.sync.ProvisioningResult;
@@ -48,7 +42,6 @@ import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
-import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.provisioning.api.TimeoutException;
@@ -68,9 +61,9 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
     @Autowired
     protected MappingUtils mappingUtils;
 
-    protected abstract String getName(Any<?, ?, ?> any);
+    protected abstract String getName(Any<?, ?> any);
 
-    protected void deprovision(final Any<?, ?, ?> any) {
+    protected void deprovision(final Any<?, ?> any) {
         AnyTO before = getAnyTO(any.getKey());
 
         List<String> noPropResources = new ArrayList<>(before.getResources());
@@ -83,7 +76,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
                 noPropResources));
     }
 
-    protected void provision(final Any<?, ?, ?> any, final Boolean enabled) {
+    protected void provision(final Any<?, ?> any, final Boolean enabled) {
         AnyTO before = getAnyTO(any.getKey());
 
         List<String> noPropResources = new ArrayList<>(before.getResources());
@@ -101,7 +94,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
     }
 
     @SuppressWarnings("unchecked")
-    protected void link(final Any<?, ?, ?> any, final Boolean unlink) {
+    protected void link(final Any<?, ?> any, final Boolean unlink) {
         AnyPatch patch = newPatch(any.getKey());
         patch.getResources().add(new StringPatchItem.Builder().
                 operation(unlink ? PatchOperation.DELETE : PatchOperation.ADD_REPLACE).
@@ -111,7 +104,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
     }
 
     @SuppressWarnings("unchecked")
-    protected void unassign(final Any<?, ?, ?> any) {
+    protected void unassign(final Any<?, ?> any) {
         AnyPatch patch = newPatch(any.getKey());
         patch.getResources().add(new StringPatchItem.Builder().
                 operation(PatchOperation.DELETE).
@@ -122,7 +115,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         deprovision(any);
     }
 
-    protected void assign(final Any<?, ?, ?> any, final Boolean enabled) {
+    protected void assign(final Any<?, ?> any, final Boolean enabled) {
         AnyPatch patch = newPatch(any.getKey());
         patch.getResources().add(new StringPatchItem.Builder().
                 operation(PatchOperation.ADD_REPLACE).
@@ -141,7 +134,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
             obj = profile.getConnector().getObject(
                     objectClass,
                     uid,
-                    profile.getConnector().getOperationOptions(Collections.<MappingItem>emptySet()));
+                    profile.getConnector().getOperationOptions(IteratorUtils.<MappingItem>emptyIterator()));
         } catch (TimeoutException toe) {
             LOG.debug("Request timeout", toe);
             throw toe;
@@ -155,7 +148,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
     @Transactional(propagation = Propagation.REQUIRES_NEW)
     @Override
     public boolean handle(final long anyKey) {
-        Any<?, ?, ?> any = null;
+        Any<?, ?> any = null;
         try {
             any = getAny(anyKey);
             doHandle(any);
@@ -176,7 +169,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         }
     }
 
-    protected final void doHandle(final Any<?, ?, ?> any) throws JobExecutionException {
+    protected final void doHandle(final Any<?, ?> any) throws JobExecutionException {
         AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
 
         ProvisioningResult result = new ProvisioningResult();
@@ -406,33 +399,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         }
     }
 
-    protected Any<?, ?, ?> update(final Any<?, ?, ?> any, final Boolean enabled) {
-        Set<AttrPatch> vattrs = new HashSet<>();
-
-        // Search for all mapped vattrs
-        Mapping mapping = profile.getTask().getResource().getProvision(any.getType()).getMapping();
-        for (MappingItem mappingItem : mapping.getItems()) {
-            if (mappingItem.getIntMappingType() == IntMappingType.UserVirtualSchema) {
-                vattrs.add(new AttrPatch.Builder().
-                        operation(PatchOperation.DELETE).
-                        attrTO(new AttrTO.Builder().schema(mappingItem.getIntAttrName()).build()).
-                        build());
-            }
-        }
-
-        // Search for all user's vattrs and:
-        // 1. add mapped vattrs not owned by the user to the set of vattrs to be removed
-        // 2. add all vattrs owned by the user to the set of vattrs to be update
-        for (VirAttr<?> vattr : any.getVirAttrs()) {
-            vattrs.add(new AttrPatch.Builder().
-                    operation(PatchOperation.ADD_REPLACE).
-                    attrTO(new AttrTO.Builder().
-                            schema(vattr.getSchema().getKey()).
-                            values(vattr.getValues()).
-                            build()).
-                    build());
-        }
-
+    protected Any<?, ?> update(final Any<?, ?> any, final Boolean enabled) {
         boolean changepwd;
         Collection<String> resourceNames;
         if (any instanceof User) {
@@ -458,7 +425,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
                 changepwd,
                 null,
                 propByRes,
-                vattrs,
+                null,
                 noPropResources));
 
         return getAny(any.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
index 2ca7eaa..3967f2b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
@@ -38,12 +38,17 @@ import org.apache.syncope.core.persistence.api.entity.task.SyncTask;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
 import org.apache.syncope.core.provisioning.api.sync.SyncActions;
 import org.apache.syncope.core.misc.security.DelegatedAdministrationException;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.provisioning.api.ProvisioningManager;
+import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
+import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
 import org.apache.syncope.core.provisioning.api.sync.IgnoreProvisionException;
 import org.apache.syncope.core.provisioning.api.sync.ProvisioningResult;
 import org.apache.syncope.core.provisioning.api.sync.SyncopeSyncResultHandler;
+import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.SyncDelta;
 import org.identityconnectors.framework.common.objects.SyncDeltaType;
 import org.quartz.JobExecutionException;
@@ -57,6 +62,12 @@ public abstract class AbstractSyncResultHandler extends AbstractSyncopeResultHan
     @Autowired
     protected SyncUtils syncUtilities;
 
+    @Autowired
+    protected VirSchemaDAO virSchemaDAO;
+
+    @Autowired
+    protected VirAttrCache virAttrCache;
+
     protected abstract String getName(AnyTO anyTO);
 
     protected abstract ProvisioningManager<?, ?> getProvisioningManager();
@@ -656,6 +667,8 @@ public abstract class AbstractSyncResultHandler extends AbstractSyncopeResultHan
 
         try {
             List<Long> anyKeys = syncUtilities.findExisting(uid, delta.getObject(), provision, anyUtils);
+            LOG.debug("Match(es) found for {} as {}: {}",
+                    delta.getUid().getUidValue(), delta.getObject().getObjectClass(), anyKeys);
 
             if (anyKeys.size() > 1) {
                 switch (profile.getResAct()) {
@@ -671,7 +684,7 @@ public abstract class AbstractSyncResultHandler extends AbstractSyncopeResultHan
                         break;
 
                     default:
-                    // keep anyIds as is
+                    // keep anyKeys unmodified
                 }
             }
 
@@ -694,25 +707,52 @@ public abstract class AbstractSyncResultHandler extends AbstractSyncopeResultHan
                         // do nothing
                     }
                 } else {
+                    // update VirAttrCache
+                    for (VirSchema virSchema : virSchemaDAO.findByProvision(provision)) {
+                        Attribute attr = delta.getObject().getAttributeByName(virSchema.getExtAttrName());
+                        for (Long anyKey : anyKeys) {
+                            if (attr == null) {
+                                virAttrCache.expire(
+                                        provision.getAnyType().getKey(),
+                                        anyKey,
+                                        virSchema.getKey());
+                            } else {
+                                VirAttrCacheValue cacheValue = new VirAttrCacheValue();
+                                cacheValue.setValues(attr.getValue());
+                                virAttrCache.put(
+                                        provision.getAnyType().getKey(),
+                                        anyKey,
+                                        virSchema.getKey(),
+                                        cacheValue);
+                            }
+                        }
+                    }
+
                     switch (profile.getTask().getMatchingRule()) {
                         case UPDATE:
                             profile.getResults().addAll(update(delta, anyKeys, provision));
                             break;
+
                         case DEPROVISION:
                             profile.getResults().addAll(deprovision(delta, anyKeys, provision, false));
                             break;
+
                         case UNASSIGN:
                             profile.getResults().addAll(deprovision(delta, anyKeys, provision, true));
                             break;
+
                         case LINK:
                             profile.getResults().addAll(link(delta, anyKeys, provision, false));
                             break;
+
                         case UNLINK:
                             profile.getResults().addAll(link(delta, anyKeys, provision, true));
                             break;
+
                         case IGNORE:
                             profile.getResults().addAll(ignore(delta, provision, true));
                             break;
+
                         default:
                         // do nothing
                     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncopeResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncopeResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncopeResultHandler.java
index 2527d5f..570cb76 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncopeResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncopeResultHandler.java
@@ -137,7 +137,7 @@ public abstract class AbstractSyncopeResultHandler<T extends ProvisioningTask, A
 
     protected abstract AnyTO getAnyTO(long key);
 
-    protected abstract Any<?, ?, ?> getAny(long key);
+    protected abstract Any<?, ?> getAny(long key);
 
     protected abstract AnyPatch newPatch(final long key);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AnyObjectPushResultHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AnyObjectPushResultHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AnyObjectPushResultHandlerImpl.java
index 755e818..7d9ab24 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AnyObjectPushResultHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AnyObjectPushResultHandlerImpl.java
@@ -36,12 +36,12 @@ public class AnyObjectPushResultHandlerImpl extends AbstractPushResultHandler im
     }
 
     @Override
-    protected String getName(final Any<?, ?, ?> any) {
+    protected String getName(final Any<?, ?> any) {
         return StringUtils.EMPTY;
     }
 
     @Override
-    protected Any<?, ?, ?> getAny(final long key) {
+    protected Any<?, ?> getAny(final long key) {
         try {
             return anyObjectDAO.authFind(key);
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AnyObjectSyncResultHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AnyObjectSyncResultHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AnyObjectSyncResultHandlerImpl.java
index 02f0b67..079529d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AnyObjectSyncResultHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AnyObjectSyncResultHandlerImpl.java
@@ -54,7 +54,7 @@ public class AnyObjectSyncResultHandlerImpl extends AbstractSyncResultHandler im
     }
 
     @Override
-    protected Any<?, ?, ?> getAny(final long key) {
+    protected Any<?, ?> getAny(final long key) {
         try {
             return anyObjectDAO.authFind(key);
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/DefaultPushActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/DefaultPushActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/DefaultPushActions.java
index a99b3e5..15f06e0 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/DefaultPushActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/DefaultPushActions.java
@@ -34,49 +34,49 @@ public abstract class DefaultPushActions implements PushActions {
     }
 
     @Override
-    public <A extends Any<?, ?, ?>> A beforeAssign(final ProvisioningProfile<?, ?> profile, final A any)
+    public <A extends Any<?, ?>> A beforeAssign(final ProvisioningProfile<?, ?> profile, final A any)
             throws JobExecutionException {
 
         return any;
     }
 
     @Override
-    public <A extends Any<?, ?, ?>> A beforeProvision(final ProvisioningProfile<?, ?> profile, final A any)
+    public <A extends Any<?, ?>> A beforeProvision(final ProvisioningProfile<?, ?> profile, final A any)
             throws JobExecutionException {
 
         return any;
     }
 
     @Override
-    public <A extends Any<?, ?, ?>> A beforeLink(final ProvisioningProfile<?, ?> profile, final A any)
+    public <A extends Any<?, ?>> A beforeLink(final ProvisioningProfile<?, ?> profile, final A any)
             throws JobExecutionException {
 
         return any;
     }
 
     @Override
-    public <A extends Any<?, ?, ?>> A beforeUnassign(final ProvisioningProfile<?, ?> profile, final A any)
+    public <A extends Any<?, ?>> A beforeUnassign(final ProvisioningProfile<?, ?> profile, final A any)
             throws JobExecutionException {
 
         return any;
     }
 
     @Override
-    public <A extends Any<?, ?, ?>> A beforeDeprovision(final ProvisioningProfile<?, ?> profile, final A any)
+    public <A extends Any<?, ?>> A beforeDeprovision(final ProvisioningProfile<?, ?> profile, final A any)
             throws JobExecutionException {
 
         return any;
     }
 
     @Override
-    public <A extends Any<?, ?, ?>> A beforeUnlink(final ProvisioningProfile<?, ?> profile, final A any)
+    public <A extends Any<?, ?>> A beforeUnlink(final ProvisioningProfile<?, ?> profile, final A any)
             throws JobExecutionException {
 
         return any;
     }
 
     @Override
-    public <A extends Any<?, ?, ?>> void onError(
+    public <A extends Any<?, ?>> void onError(
             final ProvisioningProfile<?, ?> profile, final A any, final ProvisioningResult result,
             final Exception error) throws JobExecutionException {
 
@@ -84,7 +84,7 @@ public abstract class DefaultPushActions implements PushActions {
     }
 
     @Override
-    public <A extends Any<?, ?, ?>> void after(
+    public <A extends Any<?, ?>> void after(
             final ProvisioningProfile<?, ?> profile, final A any, final ProvisioningResult result)
             throws JobExecutionException {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/GroupPushResultHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/GroupPushResultHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/GroupPushResultHandlerImpl.java
index 2fd1df7..212eb84 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/GroupPushResultHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/GroupPushResultHandlerImpl.java
@@ -36,12 +36,12 @@ public class GroupPushResultHandlerImpl extends AbstractPushResultHandler implem
     }
 
     @Override
-    protected String getName(final Any<?, ?, ?> any) {
+    protected String getName(final Any<?, ?> any) {
         return Group.class.cast(any).getName();
     }
 
     @Override
-    protected Any<?, ?, ?> getAny(final long key) {
+    protected Any<?, ?> getAny(final long key) {
         try {
             return groupDAO.authFind(key);
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/GroupSyncResultHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/GroupSyncResultHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/GroupSyncResultHandlerImpl.java
index 2d803b2..c3b9eda 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/GroupSyncResultHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/GroupSyncResultHandlerImpl.java
@@ -63,7 +63,7 @@ public class GroupSyncResultHandlerImpl extends AbstractSyncResultHandler implem
     }
 
     @Override
-    protected Any<?, ?, ?> getAny(final long key) {
+    protected Any<?, ?> getAny(final long key) {
         try {
             return groupDAO.authFind(key);
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobDelegate.java
index ff6ff21..e13407d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobDelegate.java
@@ -145,13 +145,13 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
 
                 int count = anyDAO.count(SyncopeConstants.FULL_ADMIN_REALMS);
                 for (int page = 1; page <= (count / PAGE_SIZE) + 1; page++) {
-                    List<? extends Any<?, ?, ?>> localAnys = StringUtils.isBlank(filter)
+                    List<? extends Any<?, ?>> localAnys = StringUtils.isBlank(filter)
                             ? anyDAO.findAll(SyncopeConstants.FULL_ADMIN_REALMS, page, PAGE_SIZE)
                             : searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS,
                                     SearchCondConverter.convert(filter),
                                     Collections.<OrderByClause>emptyList(), provision.getAnyType().getKind());
 
-                    for (Any<?, ?, ?> any : localAnys) {
+                    for (Any<?, ?> any : localAnys) {
                         SyncopePushResultHandler handler;
                         switch (provision.getAnyType().getKind()) {
                             case USER:

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncJobDelegate.java
index 3f19afc..890cece 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncJobDelegate.java
@@ -19,15 +19,22 @@
 package org.apache.syncope.core.provisioning.java.sync;
 
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import org.apache.commons.collections4.IteratorUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.policy.SyncPolicySpec;
 import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
 import org.apache.syncope.core.persistence.api.entity.task.SyncTask;
@@ -52,6 +59,9 @@ public class SyncJobDelegate extends AbstractProvisioningJobDelegate<SyncTask> {
     private GroupDAO groupDAO;
 
     @Autowired
+    private VirSchemaDAO virSchemaDAO;
+
+    @Autowired
     protected SyncUtils syncUtils;
 
     protected void setGroupOwners(final GroupSyncResultHandler ghandler) {
@@ -163,12 +173,25 @@ public class SyncJobDelegate extends AbstractProvisioningJobDelegate<SyncTask> {
                         latestSyncToken = connector.getLatestSyncToken(provision.getObjectClass());
                     }
 
+                    Set<MappingItem> linkinMappingItems = new HashSet<>();
+                    for (VirSchema virSchema : virSchemaDAO.findByProvision(provision)) {
+                        linkinMappingItems.add(virSchema.asLinkingMappingItem());
+                    }
+                    Iterator<MappingItem> mapItems = IteratorUtils.chainedIterator(
+                            provision.getMapping().getItems().iterator(),
+                            linkinMappingItems.iterator());
+
                     if (syncTask.isFullReconciliation()) {
-                        connector.getAllObjects(provision.getObjectClass(), handler,
-                                connector.getOperationOptions(provision.getMapping().getItems()));
+                        connector.getAllObjects(
+                                provision.getObjectClass(),
+                                handler,
+                                connector.getOperationOptions(mapItems));
                     } else {
-                        connector.sync(provision.getObjectClass(), provision.getSyncToken(), handler,
-                                connector.getOperationOptions(provision.getMapping().getItems()));
+                        connector.sync(
+                                provision.getObjectClass(),
+                                provision.getSyncToken(),
+                                handler,
+                                connector.getOperationOptions(mapItems));
                     }
 
                     if (!dryRun && !syncTask.isFullReconciliation()) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java
index 0c01254..eefccad 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java
@@ -128,7 +128,7 @@ public class SyncUtils {
                         return found.add(obj);
                     }
                 },
-                connector.getOperationOptions(MappingUtils.getSyncMappingItems(provision)));
+                connector.getOperationOptions(MappingUtils.getSyncMappingItems(provision).iterator()));
 
         if (found.isEmpty()) {
             LOG.debug("No {} found on {} with __NAME__ {}", provision.getObjectClass(), resource, name);
@@ -199,9 +199,9 @@ public class SyncUtils {
                     }
                 }
 
-                List<? extends Any<?, ?, ?>> anys =
+                List<? extends Any<?, ?>> anys =
                         getAnyDAO(connObjectKeyItem).findByAttrValue(connObjectKeyItem.getIntAttrName(), value);
-                for (Any<?, ?, ?> any : anys) {
+                for (Any<?, ?> any : anys) {
                     result.add(any.getKey());
                 }
                 break;
@@ -210,7 +210,7 @@ public class SyncUtils {
             case GroupDerivedSchema:
             case AnyObjectDerivedSchema:
                 anys = getAnyDAO(connObjectKeyItem).findByDerAttrValue(connObjectKeyItem.getIntAttrName(), transfUid);
-                for (Any<?, ?, ?> any : anys) {
+                for (Any<?, ?> any : anys) {
                     result.add(any.getKey());
                 }
                 break;
@@ -218,7 +218,7 @@ public class SyncUtils {
             case UserKey:
             case GroupKey:
             case AnyObjectKey:
-                Any<?, ?, ?> any = getAnyDAO(connObjectKeyItem).find(Long.parseLong(transfUid));
+                Any<?, ?> any = getAnyDAO(connObjectKeyItem).find(Long.parseLong(transfUid));
                 if (any != null) {
                     result.add(any.getKey());
                 }
@@ -249,7 +249,7 @@ public class SyncUtils {
             final ConnectorObject connObj, final SyncCorrelationRule rule, final AnyTypeKind type) {
 
         List<Long> result = new ArrayList<>();
-        for (Any<?, ?, ?> any : searchDAO.search(
+        for (Any<?, ?> any : searchDAO.search(
                 SyncopeConstants.FULL_ADMIN_REALMS,
                 rule.getSearchCond(connObj),
                 Collections.<OrderByClause>emptyList(),

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/UserPushResultHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/UserPushResultHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/UserPushResultHandlerImpl.java
index 5829216..8f70560 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/UserPushResultHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/UserPushResultHandlerImpl.java
@@ -41,7 +41,7 @@ public class UserPushResultHandlerImpl extends AbstractPushResultHandler impleme
     }
 
     @Override
-    protected void provision(final Any<?, ?, ?> any, final Boolean enabled) {
+    protected void provision(final Any<?, ?> any, final Boolean enabled) {
         AnyTO before = getAnyTO(any.getKey());
 
         List<String> noPropResources = new ArrayList<>(before.getResources());
@@ -60,12 +60,12 @@ public class UserPushResultHandlerImpl extends AbstractPushResultHandler impleme
     }
 
     @Override
-    protected String getName(final Any<?, ?, ?> any) {
+    protected String getName(final Any<?, ?> any) {
         return User.class.cast(any).getUsername();
     }
 
     @Override
-    protected Any<?, ?, ?> getAny(final long key) {
+    protected Any<?, ?> getAny(final long key) {
         try {
             return userDAO.authFind(key);
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/UserSyncResultHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/UserSyncResultHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/UserSyncResultHandlerImpl.java
index c5e918a..23e209c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/UserSyncResultHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/UserSyncResultHandlerImpl.java
@@ -54,7 +54,7 @@ public class UserSyncResultHandlerImpl extends AbstractSyncResultHandler impleme
     }
 
     @Override
-    protected Any<?, ?, ?> getAny(final long key) {
+    protected Any<?, ?> getAny(final long key) {
         try {
             return userDAO.authFind(key);
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/ThreadLocalCleanupListener.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/ThreadLocalCleanupListener.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/ThreadLocalCleanupListener.java
index 39f5573..fe19915 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/ThreadLocalCleanupListener.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/ThreadLocalCleanupListener.java
@@ -20,7 +20,7 @@ package org.apache.syncope.core.rest.cxf;
 
 import javax.servlet.ServletRequestEvent;
 import javax.servlet.ServletRequestListener;
-import org.apache.syncope.core.misc.DataFormat;
+import org.apache.syncope.core.misc.FormatUtils;
 import org.identityconnectors.common.l10n.CurrentLocale;
 import org.identityconnectors.framework.impl.api.local.ThreadClassLoaderManager;
 
@@ -36,7 +36,7 @@ public class ThreadLocalCleanupListener implements ServletRequestListener {
 
     @Override
     public void requestDestroyed(final ServletRequestEvent sre) {
-        DataFormat.clear();
+        FormatUtils.clear();
 
         ThreadClassLoaderManager.clearInstance();
         CurrentLocale.clear();

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
index d33cde2..4258e64 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
@@ -179,23 +179,20 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
 
         P patch = newPatch(key);
 
-        Set<AttrPatch> patches;
         switch (schemaType) {
             case DERIVED:
-                patches = patch.getDerAttrs();
+                patch.getDerAttrs().add(new AttrPatch.Builder().operation(operation).attrTO(attrTO).build());
                 break;
 
             case VIRTUAL:
-                patches = patch.getVirAttrs();
+                patch.getVirAttrs().add(attrTO);
                 break;
 
             case PLAIN:
             default:
-                patches = patch.getPlainAttrs();
+                patch.getPlainAttrs().add(new AttrPatch.Builder().operation(operation).attrTO(attrTO).build());
         }
 
-        patches.add(new AttrPatch.Builder().operation(operation).attrTO(attrTO).build());
-
         update(patch);
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
index 158cc09..3f2b690 100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
@@ -25,7 +25,6 @@ import org.apache.camel.Processor;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.syncope.common.lib.patch.AnyObjectPatch;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
@@ -60,17 +59,6 @@ public class AnyObjectUpdateProcessor implements Processor {
         AnyObjectPatch anyObjectPatch = exchange.getProperty("anyPatch", AnyObjectPatch.class);
         Set<String> excludedResources = exchange.getProperty("excludedResources", Set.class);
 
-        // SYNCOPE-459: take care of user virtual attributes ...
-        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                updated.getResult(),
-                AnyTypeKind.ANY_OBJECT,
-                anyObjectPatch.getVirAttrs());
-        if (updated.getPropByRes() == null) {
-            updated.setPropByRes(propByResVirAttr);
-        } else {
-            updated.getPropByRes().merge(propByResVirAttr);
-        }
-
         List<PropagationTask> tasks = propagationManager.getUpdateTasks(
                 AnyTypeKind.ANY_OBJECT,
                 updated.getResult(),
@@ -79,7 +67,6 @@ public class AnyObjectUpdateProcessor implements Processor {
                 updated.getPropByRes(),
                 anyObjectPatch.getVirAttrs(),
                 excludedResources);
-
         PropagationReporter propagationReporter =
                 ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
         try {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/GroupUpdateProcessor.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/GroupUpdateProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/GroupUpdateProcessor.java
index 22868bf..599f54b 100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/GroupUpdateProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/GroupUpdateProcessor.java
@@ -25,7 +25,6 @@ import org.apache.camel.Processor;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.syncope.common.lib.patch.GroupPatch;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
@@ -60,17 +59,6 @@ public class GroupUpdateProcessor implements Processor {
         GroupPatch groupPatch = exchange.getProperty("anyPatch", GroupPatch.class);
         Set<String> excludedResources = exchange.getProperty("excludedResources", Set.class);
 
-        // SYNCOPE-459: take care of user virtual attributes ...
-        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                updated.getResult(),
-                AnyTypeKind.GROUP,
-                groupPatch.getVirAttrs());
-        if (updated.getPropByRes() == null) {
-            updated.setPropByRes(propByResVirAttr);
-        } else {
-            updated.getPropByRes().merge(propByResVirAttr);
-        }
-
         List<PropagationTask> tasks = propagationManager.getUpdateTasks(
                 AnyTypeKind.GROUP,
                 updated.getResult(),
@@ -79,7 +67,6 @@ public class GroupUpdateProcessor implements Processor {
                 updated.getPropByRes(),
                 groupPatch.getVirAttrs(),
                 excludedResources);
-
         PropagationReporter propagationReporter =
                 ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
         try {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateInSyncProcessor.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateInSyncProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateInSyncProcessor.java
index ffdd5d2..8b49a5d 100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateInSyncProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateInSyncProcessor.java
@@ -54,12 +54,10 @@ public class UserUpdateInSyncProcessor implements Processor {
         WorkflowResult<Pair<UserPatch, Boolean>> updated = (WorkflowResult) exchange.getIn().getBody();
         Set<String> excludedResources = exchange.getProperty("excludedResources", Set.class);
 
-        PropagationReporter propagationReporter =
-                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
-
         List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
                 updated, updated.getResult().getKey().getPassword() != null, excludedResources);
-
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
         try {
             taskExecutor.execute(tasks, propagationReporter);
         } catch (PropagationException e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateProcessor.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateProcessor.java
index bd0df76..8f175dd 100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserUpdateProcessor.java
@@ -24,8 +24,6 @@ import org.apache.camel.Processor;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.patch.UserPatch;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
@@ -57,30 +55,15 @@ public class UserUpdateProcessor implements Processor {
     @SuppressWarnings("unchecked")
     public void process(final Exchange exchange) {
         WorkflowResult<Pair<UserPatch, Boolean>> updated = (WorkflowResult) exchange.getIn().getBody();
-        UserPatch userPatch = exchange.getProperty("actual", UserPatch.class);
-
-        // SYNCOPE-459: take care of user virtual attributes ...
-        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                updated.getResult().getKey().getKey(),
-                AnyTypeKind.USER,
-                userPatch.getVirAttrs());
-        if (updated.getPropByRes() == null) {
-            updated.setPropByRes(propByResVirAttr);
-        } else {
-            updated.getPropByRes().merge(propByResVirAttr);
-        }
 
         List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(updated);
-
         PropagationReporter propagationReporter =
                 ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
-        if (!tasks.isEmpty()) {
-            try {
-                taskExecutor.execute(tasks, propagationReporter);
-            } catch (PropagationException e) {
-                LOG.error("Error propagation primary resource", e);
-                propagationReporter.onPrimaryResourceFailure(tasks);
-            }
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
         }
 
         exchange.getOut().setBody(new ImmutablePair<>(

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/fit/console-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/console-reference/pom.xml b/fit/console-reference/pom.xml
index b518886..3c89990 100644
--- a/fit/console-reference/pom.xml
+++ b/fit/console-reference/pom.xml
@@ -457,19 +457,19 @@ ORYX.Editor.createByUrl = function(modelUrl){"/>
                   <resource>
                     <directory>${basedir}/../../core/logic/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>logicContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
                     <directory>${basedir}/../../core/rest-cxf/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>restCXFContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
                     <directory>${basedir}/../../core/misc/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>securityContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
@@ -478,7 +478,7 @@ ORYX.Editor.createByUrl = function(modelUrl){"/>
                   <resource>
                     <directory>${basedir}/../../core/persistence-jpa/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>persistenceContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
@@ -487,7 +487,7 @@ ORYX.Editor.createByUrl = function(modelUrl){"/>
                   <resource>
                     <directory>${basedir}/../../core/provisioning-java/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>provisioningContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
@@ -496,85 +496,22 @@ ORYX.Editor.createByUrl = function(modelUrl){"/>
                   <resource>
                     <directory>${basedir}/../../core/workflow-java/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>workflowContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
                     <directory>${basedir}/../../core/workflow-activiti/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>workflowActivitiContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
                     <directory>${basedir}/../../ext/camel/provisioning-camel/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
-                    </excludes>
-                  </resource>
-
-                  <resource>
-                    <directory>${basedir}/../../common/lib/target/classes</directory>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../common/rest-api/target/classes</directory>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../core/logic/target/classes</directory>
-                    <excludes>
-                      <exclude>*Context.xml</exclude>
-                    </excludes>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../core/rest-cxf/target/classes</directory>
-                    <excludes>
-                      <exclude>*Context.xml</exclude>
-                    </excludes>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../core/misc/target/classes</directory>
-                    <excludes>
-                      <exclude>*Context.xml</exclude>
-                    </excludes>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../core/persistence-api/target/classes</directory>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../core/persistence-jpa/target/classes</directory>
-                    <excludes>
-                      <exclude>*Context.xml</exclude>
-                    </excludes>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../core/provisioning-api/target/classes</directory>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../core/provisioning-java/target/classes</directory>
-                    <excludes>
-                      <exclude>*Context.xml</exclude>
-                    </excludes>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../core/workflow-api/target/classes</directory>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../core/workflow-java/target/classes</directory>
-                    <excludes>
-                      <exclude>*Context.xml</exclude>
-                    </excludes>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../core/workflow-activiti/target/classes</directory>
-                    <excludes>
-                      <exclude>*Context.xml</exclude>
-                    </excludes>
-                  </resource>
-                  <resource>
-                    <directory>${basedir}/../../ext/camel/provisioning-camel/target/classes</directory>
-                    <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>provisioningCamelContext.xml</exclude>
                     </excludes>
                   </resource>
+                  
                   <resource>
                     <directory>${basedir}/../../client/console/target/classes</directory>
                   </resource>

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/fit/core-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 7e0fd9f..724f592 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -758,19 +758,19 @@ under the License.
                   <resource>
                     <directory>${basedir}/../../core/logic/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>logicContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
                     <directory>${basedir}/../../core/rest-cxf/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>restCXFContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
                     <directory>${basedir}/../../core/misc/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>securityContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
@@ -779,7 +779,7 @@ under the License.
                   <resource>
                     <directory>${basedir}/../../core/persistence-jpa/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>persistenceContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
@@ -788,7 +788,7 @@ under the License.
                   <resource>
                     <directory>${basedir}/../../core/provisioning-java/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>provisioningContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
@@ -797,19 +797,19 @@ under the License.
                   <resource>
                     <directory>${basedir}/../../core/workflow-java/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>workflowContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
                     <directory>${basedir}/../../core/workflow-activiti/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>workflowActivitiContext.xml</exclude>
                     </excludes>
                   </resource>
                   <resource>
                     <directory>${basedir}/../../ext/camel/provisioning-camel/target/classes</directory>
                     <excludes>
-                      <exclude>*Context.xml</exclude>
+                      <exclude>provisioningCamelContext.xml</exclude>
                     </excludes>
                   </resource>
                 </resources>

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
index 1abb943..148f0eb 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/GroupITCase.java
@@ -59,6 +59,7 @@ import org.apache.syncope.common.lib.to.PlainSchemaTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.MappingTO;
+import org.apache.syncope.common.lib.to.ProvisionTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
@@ -218,27 +219,6 @@ public class GroupITCase extends AbstractITCase {
     }
 
     @Test
-    public void updateRemovingVirAttribute() {
-        GroupTO groupTO = getBasicSampleTO("withvirtual" + getUUIDString());
-        groupTO.getVirAttrs().add(attrTO("rvirtualdata", null));
-
-        groupTO = createGroup(groupTO);
-
-        assertNotNull(groupTO);
-        assertEquals(1, groupTO.getVirAttrs().size());
-
-        GroupPatch groupPatch = new GroupPatch();
-        groupPatch.setKey(groupTO.getKey());
-        groupPatch.getVirAttrs().add(new AttrPatch.Builder().operation(PatchOperation.DELETE).
-                attrTO(new AttrTO.Builder().schema("rvirtualdata").build()).
-                build());
-
-        groupTO = updateGroup(groupPatch);
-        assertNotNull(groupTO);
-        assertTrue(groupTO.getVirAttrs().isEmpty());
-    }
-
-    @Test
     public void updateRemovingDerAttribute() {
         GroupTO groupTO = getBasicSampleTO("withderived" + getUUIDString());
         groupTO.getDerAttrs().add(attrTO("rderivedschema", null));
@@ -638,6 +618,10 @@ public class GroupITCase extends AbstractITCase {
             newLDAP.setKey("new-ldap");
             newLDAP.setPropagationPrimary(true);
 
+            for (ProvisionTO provision : newLDAP.getProvisions()) {
+                provision.getVirSchemas().clear();
+            }
+
             MappingTO mapping = newLDAP.getProvision(AnyTypeKind.GROUP.name()).getMapping();
 
             MappingItemTO connObjectKey = mapping.getConnObjectKeyItem();

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/PropagationTaskITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/PropagationTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/PropagationTaskITCase.java
index 4115bfa..7f2964f 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/PropagationTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/PropagationTaskITCase.java
@@ -85,14 +85,6 @@ public class PropagationTaskITCase extends AbstractTaskITCase {
     }
 
     @Test
-    public void issue196() {
-        TaskExecTO exec = taskService.execute(6L, false);
-        assertNotNull(exec);
-        assertEquals(0, exec.getKey());
-        assertNotNull(exec.getTask());
-    }
-
-    @Test
     public void bulkAction() {
         PagedResult<PropagationTaskTO> before = taskService.list(
                 TaskType.PROPAGATION, SyncopeClient.getTaskQueryBuilder().build());

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
index 75049da..d645c77 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java
@@ -607,6 +607,9 @@ public class SyncTaskITCase extends AbstractTaskITCase {
     @Test
     public void issueSYNCOPE307() {
         UserTO userTO = UserITCase.getUniqueSampleTO("s307@apache.org");
+        userTO.setUsername("test0");
+        userTO.getPlainAttrMap().get("firstname").getValues().clear();
+        userTO.getPlainAttrMap().get("firstname").getValues().add("nome0");
         userTO.getAuxClasses().add("csv");
 
         AttrTO csvuserid = new AttrTO();
@@ -615,37 +618,34 @@ public class SyncTaskITCase extends AbstractTaskITCase {
 
         userTO.getResources().clear();
         userTO.getResources().add(RESOURCE_NAME_WS2);
-        userTO.getResources().add(RESOURCE_NAME_CSV);
 
         userTO = createUser(userTO);
         assertNotNull(userTO);
 
         userTO = userService.read(userTO.getKey());
-        assertEquals("virtualvalue", userTO.getVirAttrMap().get("virtualdata").getValues().get(0));
+        assertTrue(userTO.getVirAttrMap().isEmpty());
 
         // Update sync task
         SyncTaskTO task = taskService.read(12L);
         assertNotNull(task);
 
-        //  add user template
         UserTO template = new UserTO();
+        template.setPassword("'password123'");
         template.getResources().add(RESOURCE_NAME_DBVIRATTR);
-
-        AttrTO userId = attrTO("userId", "'s307@apache.org'");
-        template.getPlainAttrs().add(userId);
-
-        AttrTO email = attrTO("email", "'s307@apache.org'");
-        template.getPlainAttrs().add(email);
+        template.getVirAttrs().add(attrTO("virtualdata", "'virtualvalue'"));
 
         task.getTemplates().put(AnyTypeKind.USER.name(), template);
 
         taskService.update(task);
+
+        // exec task: one user from CSV will match the user created above and template will be applied
         execProvisioningTask(taskService, task.getKey(), 50, false);
 
-        // check for sync policy
+        // check that template was successfully applied...
         userTO = userService.read(userTO.getKey());
         assertEquals("virtualvalue", userTO.getVirAttrMap().get("virtualdata").getValues().get(0));
 
+        // ...and that propagation to db succeeded
         try {
             JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
 


[07/54] [abbrv] syncope git commit: Small enhancement in ExternalResource entity validation

Posted by fm...@apache.org.
Small enhancement in ExternalResource entity validation


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

Branch: refs/heads/SYNCOPE-156
Commit: 77c2999b339ca2c3ef510578780a17a5d0c79f3e
Parents: c1bd770
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 15 12:26:24 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 15 12:26:24 2015 +0200

----------------------------------------------------------------------
 .../entity/ExternalResourceValidator.java       | 32 ++++++++++++--------
 1 file changed, 20 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/77c2999b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
index 7879661..fb5a0a9 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
@@ -32,6 +32,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
+import org.identityconnectors.framework.common.objects.ObjectClass;
 
 public class ExternalResourceValidator extends AbstractValidator<ExternalResourceCheck, ExternalResource> {
 
@@ -162,22 +163,29 @@ public class ExternalResourceValidator extends AbstractValidator<ExternalResourc
             }
         }
 
+        final Set<AnyType> anyTypes = new HashSet<>();
         final Set<String> objectClasses = new HashSet<>();
-        boolean validMappings = CollectionUtils.matchesAll(resource.getProvisions(),
-                new Predicate<Provision>() {
-
-                    @Override
-                    public boolean evaluate(final Provision provision) {
-                        if (provision.getObjectClass() != null) {
-                            objectClasses.add(provision.getObjectClass().getObjectClassValue());
-                        }
-                        return isValid(provision.getAnyType(), provision.getMapping(), context);
-                    }
-                });
+        boolean validMappings = CollectionUtils.matchesAll(resource.getProvisions(), new Predicate<Provision>() {
 
+            @Override
+            public boolean evaluate(final Provision provision) {
+                anyTypes.add(provision.getAnyType());
+                if (provision.getObjectClass() != null) {
+                    objectClasses.add(provision.getObjectClass().getObjectClassValue());
+                }
+                return isValid(provision.getAnyType(), provision.getMapping(), context);
+            }
+        });
+
+        if (anyTypes.size() < resource.getProvisions().size()) {
+            context.buildConstraintViolationWithTemplate(getTemplate(EntityViolationType.InvalidResource,
+                    "Each provision requires a different " + AnyType.class.getSimpleName())).
+                    addPropertyNode("provisions").addConstraintViolation();
+            return false;
+        }
         if (objectClasses.size() < resource.getProvisions().size()) {
             context.buildConstraintViolationWithTemplate(getTemplate(EntityViolationType.InvalidResource,
-                    "Each provision requires a different ObjectClass")).
+                    "Each provision requires a different" + ObjectClass.class.getSimpleName())).
                     addPropertyNode("provisions").addConstraintViolation();
             return false;
         }


[06/54] [abbrv] syncope git commit: Upgrading Glassfish to 4.1.1

Posted by fm...@apache.org.
Upgrading Glassfish to 4.1.1


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

Branch: refs/heads/SYNCOPE-156
Commit: c1bd770a0b1b8738ea59e90de40238290f181698
Parents: 2011671
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 15 12:21:40 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 15 12:21:40 2015 +0200

----------------------------------------------------------------------
 fit/core-reference/pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/c1bd770a/fit/core-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 90e4df9..8f4f62a 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -552,7 +552,7 @@ under the License.
               <container>
                 <containerId>glassfish4x</containerId>
                 <zipUrlInstaller>
-                  <url>http://download.java.net/glassfish/4.1/release/glassfish-4.1.zip</url>
+                  <url>http://download.oracle.com/glassfish/4.1.1/release/glassfish-4.1.1.zip</url>
                   <downloadDir>${settings.localRepository}/org/codehaus/cargo/cargo-container-archives</downloadDir>
                   <extractDir>${project.build.directory}/cargo/extract</extractDir>
                 </zipUrlInstaller>


[05/54] [abbrv] syncope git commit: [SYNCOPE-710] Merge from 1_2_X

Posted by fm...@apache.org.
[SYNCOPE-710] Merge from 1_2_X


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

Branch: refs/heads/SYNCOPE-156
Commit: 2011671c93ac23a2397bcc8be39a1ca191ed035f
Parents: 4133c24 2524280
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 15 12:05:33 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 15 12:05:33 2015 +0200

----------------------------------------------------------------------
 .../DefaultAnyObjectProvisioningManager.java    | 28 +++++--------
 .../java/DefaultGroupProvisioningManager.java   | 28 +++++--------
 .../java/DefaultUserProvisioningManager.java    | 42 +++++++++-----------
 .../java/data/UserDataBinderImpl.java           | 13 +++---
 .../propagation/PropagationManagerImpl.java     |  8 +---
 .../activiti/ActivitiUserWorkflowAdapter.java   | 17 +++++++-
 .../workflow/activiti/task/PasswordReset.java   | 24 ++++++++++-
 .../core/workflow/activiti/task/Update.java     | 21 +---------
 .../core/workflow/api/UserWorkflowAdapter.java  |  3 +-
 .../java/AbstractUserWorkflowAdapter.java       |  9 +++--
 .../java/DefaultUserWorkflowAdapter.java        | 33 ++++++---------
 .../processor/AnyObjectUpdateProcessor.java     | 29 +++++---------
 .../camel/processor/GroupUpdateProcessor.java   | 29 +++++---------
 .../processor/UserConfirmPwdResetProcessor.java | 14 ++-----
 .../UserStatusPropagationProcessor.java         | 15 ++++---
 .../camel/processor/UserUpdateProcessor.java    | 21 +++++-----
 .../syncope/fit/core/reference/UserITCase.java  | 34 +++++++++++++++-
 .../fit/core/reference/VirAttrITCase.java       |  4 +-
 18 files changed, 188 insertions(+), 184 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
----------------------------------------------------------------------
diff --cc core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
index bc1dbc2,0000000..d332e23
mode 100644,000000..100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
@@@ -1,226 -1,0 +1,220 @@@
 +/*
 + * 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.provisioning.java;
 +
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.List;
 +import java.util.Set;
 +import org.apache.commons.collections4.CollectionUtils;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.patch.AnyObjectPatch;
 +import org.apache.syncope.common.lib.to.PropagationStatus;
 +import org.apache.syncope.common.lib.to.AnyObjectTO;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.common.lib.types.ResourceOperation;
 +import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 +import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 +import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +
 +public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisioningManager {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(AnyObjectProvisioningManager.class);
 +
 +    @Autowired
 +    protected AnyObjectWorkflowAdapter awfAdapter;
 +
 +    @Autowired
 +    protected PropagationManager propagationManager;
 +
 +    @Autowired
 +    protected PropagationTaskExecutor taskExecutor;
 +
 +    @Autowired
 +    protected VirAttrHandler virtAttrHandler;
 +
 +    @Autowired
 +    protected AnyObjectDAO anyObjectDAO;
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> create(final AnyObjectTO anyObjectTO) {
 +        return create(anyObjectTO, Collections.<String>emptySet());
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> create(
 +            final AnyObjectTO anyObjectTO, final Set<String> excludedResources) {
 +
 +        WorkflowResult<Long> created = awfAdapter.create(anyObjectTO);
 +
 +        List<PropagationTask> tasks = propagationManager.getCreateTasks(
 +                AnyTypeKind.ANY_OBJECT,
 +                created.getResult(),
 +                created.getPropByRes(),
 +                anyObjectTO.getVirAttrs(),
 +                excludedResources);
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        return new ImmutablePair<>(created.getResult(), propagationReporter.getStatuses());
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> update(final AnyObjectPatch anyObjectPatch) {
 +        return update(anyObjectPatch, Collections.<String>emptySet());
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> update(
 +            final AnyObjectPatch anyObjectPatch, final Set<String> excludedResources) {
 +
 +        WorkflowResult<Long> updated = awfAdapter.update(anyObjectPatch);
 +
++        // SYNCOPE-459: take care of user virtual attributes ...
++        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
++                updated.getResult(),
++                AnyTypeKind.ANY_OBJECT,
++                anyObjectPatch.getVirAttrs());
++        if (updated.getPropByRes() == null) {
++            updated.setPropByRes(propByResVirAttr);
++        } else {
++            updated.getPropByRes().merge(propByResVirAttr);
++        }
++
 +        List<PropagationTask> tasks = propagationManager.getUpdateTasks(
 +                AnyTypeKind.ANY_OBJECT,
 +                updated.getResult(),
 +                false,
 +                null,
 +                updated.getPropByRes(),
 +                anyObjectPatch.getVirAttrs(),
 +                excludedResources);
-         if (tasks.isEmpty()) {
-             // SYNCOPE-459: take care of user virtual attributes ...
-             PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                     updated.getResult(),
-                     AnyTypeKind.ANY_OBJECT,
-                     anyObjectPatch.getVirAttrs());
-             tasks.addAll(!propByResVirAttr.isEmpty()
-                     ? propagationManager.getUpdateTasks(
-                             AnyTypeKind.ANY_OBJECT,
-                             updated.getResult(),
-                             false,
-                             null,
-                             updated.getPropByRes(),
-                             anyObjectPatch.getVirAttrs(),
-                             null)
-                     : Collections.<PropagationTask>emptyList());
-         }
 +
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        return new ImmutablePair<>(updated.getResult(), propagationReporter.getStatuses());
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> delete(final Long key) {
 +        return delete(key, Collections.<String>emptySet());
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> delete(final Long key, final Set<String> excludedResources) {
 +        List<PropagationTask> tasks = propagationManager.getDeleteTasks(
 +                AnyTypeKind.ANY_OBJECT,
 +                key,
 +                null,
 +                excludedResources);
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        awfAdapter.delete(key);
 +
 +        return propagationReporter.getStatuses();
 +    }
 +
 +    @Override
 +    public Long unlink(final AnyObjectPatch anyObjectPatch) {
 +        return awfAdapter.update(anyObjectPatch).getResult();
 +    }
 +
 +    @Override
 +    public Long link(final AnyObjectPatch anyObjectPatch) {
 +        return awfAdapter.update(anyObjectPatch).getResult();
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> provision(final Long key, final Collection<String> resources) {
 +        PropagationByResource propByRes = new PropagationByResource();
 +        propByRes.addAll(ResourceOperation.UPDATE, resources);
 +
 +        List<PropagationTask> tasks = propagationManager.getUpdateTasks(
 +                AnyTypeKind.ANY_OBJECT,
 +                key,
 +                false,
 +                null,
 +                propByRes,
 +                null,
 +                null);
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +        return propagationReporter.getStatuses();
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> deprovision(final Long key, final Collection<String> resources) {
 +        PropagationByResource propByRes = new PropagationByResource();
 +        propByRes.addAll(ResourceOperation.DELETE, resources);
 +
 +        List<PropagationTask> tasks = propagationManager.getDeleteTasks(
 +                AnyTypeKind.ANY_OBJECT,
 +                key,
 +                propByRes,
 +                CollectionUtils.removeAll(anyObjectDAO.findAllResourceNames(anyObjectDAO.authFind(key)), resources));
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +        return propagationReporter.getStatuses();
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
----------------------------------------------------------------------
diff --cc core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
index b933488,0000000..0fff2a3
mode 100644,000000..100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
@@@ -1,285 -1,0 +1,279 @@@
 +/*
 + * 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.provisioning.java;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.Set;
 +import org.apache.commons.collections4.CollectionUtils;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.patch.GroupPatch;
 +import org.apache.syncope.common.lib.to.AttrTO;
 +import org.apache.syncope.common.lib.to.PropagationStatus;
 +import org.apache.syncope.common.lib.to.GroupTO;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.common.lib.types.ResourceOperation;
 +import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 +import org.apache.syncope.core.provisioning.api.GroupProvisioningManager;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 +import org.apache.syncope.core.workflow.api.GroupWorkflowAdapter;
 +
 +public class DefaultGroupProvisioningManager implements GroupProvisioningManager {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(GroupProvisioningManager.class);
 +
 +    @Autowired
 +    protected GroupWorkflowAdapter gwfAdapter;
 +
 +    @Autowired
 +    protected PropagationManager propagationManager;
 +
 +    @Autowired
 +    protected PropagationTaskExecutor taskExecutor;
 +
 +    @Autowired
 +    protected GroupDAO groupDAO;
 +
 +    @Autowired
 +    protected VirAttrHandler virtAttrHandler;
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> create(final GroupTO group) {
 +        return create(group, Collections.<String>emptySet());
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> create(final GroupTO groupTO, final Set<String> excludedResources) {
 +        WorkflowResult<Long> created = gwfAdapter.create(groupTO);
 +
 +        List<PropagationTask> tasks = propagationManager.getCreateTasks(
 +                AnyTypeKind.GROUP,
 +                created.getResult(),
 +                created.getPropByRes(),
 +                groupTO.getVirAttrs(),
 +                excludedResources);
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        return new ImmutablePair<>(created.getResult(), propagationReporter.getStatuses());
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> create(
 +            final GroupTO groupTO, final Map<Long, String> groupOwnerMap, final Set<String> excludedResources) {
 +
 +        WorkflowResult<Long> created = gwfAdapter.create(groupTO);
 +
 +        // see ConnObjectUtils#getAnyTOFromConnObject for GroupOwnerSchema
 +        AttrTO groupOwner = groupTO.getPlainAttrMap().get(StringUtils.EMPTY);
 +        if (groupOwner != null) {
 +            groupOwnerMap.put(created.getResult(), groupOwner.getValues().iterator().next());
 +        }
 +
 +        List<PropagationTask> tasks = propagationManager.getCreateTasks(
 +                AnyTypeKind.GROUP,
 +                created.getResult(),
 +                created.getPropByRes(),
 +                groupTO.getVirAttrs(),
 +                excludedResources);
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        return new ImmutablePair<>(created.getResult(), null);
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> update(final GroupPatch groupPatch) {
 +        return update(groupPatch, Collections.<String>emptySet());
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> update(
 +            final GroupPatch groupPatch, final Set<String> excludedResources) {
 +
 +        WorkflowResult<Long> updated = gwfAdapter.update(groupPatch);
 +
++        // SYNCOPE-459: take care of user virtual attributes ...
++        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
++                updated.getResult(),
++                AnyTypeKind.GROUP,
++                groupPatch.getVirAttrs());
++        if (updated.getPropByRes() == null) {
++            updated.setPropByRes(propByResVirAttr);
++        } else {
++            updated.getPropByRes().merge(propByResVirAttr);
++        }
++
 +        List<PropagationTask> tasks = propagationManager.getUpdateTasks(
 +                AnyTypeKind.GROUP,
 +                updated.getResult(),
 +                false,
 +                null,
 +                updated.getPropByRes(),
 +                groupPatch.getVirAttrs(),
 +                excludedResources);
-         if (tasks.isEmpty()) {
-             // SYNCOPE-459: take care of user virtual attributes ...
-             PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                     updated.getResult(),
-                     AnyTypeKind.GROUP,
-                     groupPatch.getVirAttrs());
-             tasks.addAll(!propByResVirAttr.isEmpty()
-                     ? propagationManager.getUpdateTasks(
-                             AnyTypeKind.GROUP,
-                             updated.getResult(),
-                             false,
-                             null,
-                             updated.getPropByRes(),
-                             groupPatch.getVirAttrs(),
-                             excludedResources)
-                     : Collections.<PropagationTask>emptyList());
-         }
 +
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        return new ImmutablePair<>(updated.getResult(), propagationReporter.getStatuses());
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> delete(final Long key) {
 +        return delete(key, Collections.<String>emptySet());
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> delete(final Long key, final Set<String> excludedResources) {
 +        List<PropagationTask> tasks = new ArrayList<>();
 +
 +        // Generate propagation tasks for deleting users and any objects from group resources, 
 +        // if they are on those resources only because of the reason being deleted (see SYNCOPE-357)
 +        for (Map.Entry<Long, PropagationByResource> entry
 +                : groupDAO.findUsersWithTransitiveResources(key).entrySet()) {
 +
 +            tasks.addAll(propagationManager.getDeleteTasks(
 +                    AnyTypeKind.USER,
 +                    entry.getKey(),
 +                    entry.getValue(),
 +                    excludedResources));
 +        }
 +        for (Map.Entry<Long, PropagationByResource> entry
 +                : groupDAO.findAnyObjectsWithTransitiveResources(key).entrySet()) {
 +
 +            tasks.addAll(propagationManager.getDeleteTasks(
 +                    AnyTypeKind.ANY_OBJECT,
 +                    entry.getKey(),
 +                    entry.getValue(),
 +                    excludedResources));
 +        }
 +
 +        // Generate propagation tasks for deleting this group from resources
 +        tasks.addAll(propagationManager.getDeleteTasks(
 +                AnyTypeKind.GROUP,
 +                key,
 +                null,
 +                null));
 +
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        gwfAdapter.delete(key);
 +
 +        return propagationReporter.getStatuses();
 +    }
 +
 +    @Override
 +    public Long unlink(final GroupPatch groupPatch) {
 +        WorkflowResult<Long> updated = gwfAdapter.update(groupPatch);
 +        return updated.getResult();
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> provision(final Long key, final Collection<String> resources) {
 +        PropagationByResource propByRes = new PropagationByResource();
 +        propByRes.addAll(ResourceOperation.UPDATE, resources);
 +
 +        List<PropagationTask> tasks = propagationManager.getUpdateTasks(
 +                AnyTypeKind.GROUP,
 +                key,
 +                false,
 +                null,
 +                propByRes,
 +                null,
 +                null);
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +        return propagationReporter.getStatuses();
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> deprovision(final Long key, final Collection<String> resources) {
 +        PropagationByResource propByRes = new PropagationByResource();
 +        propByRes.addAll(ResourceOperation.DELETE, resources);
 +
 +        List<PropagationTask> tasks = propagationManager.getDeleteTasks(
 +                AnyTypeKind.GROUP,
 +                key,
 +                propByRes,
 +                CollectionUtils.removeAll(groupDAO.authFind(key).getResourceNames(), resources));
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +        return propagationReporter.getStatuses();
 +    }
 +
 +    @Override
 +    public Long link(final GroupPatch groupPatch) {
 +        return gwfAdapter.update(groupPatch).getResult();
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
----------------------------------------------------------------------
diff --cc core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
index 4a302f2,0000000..a59337c
mode 100644,000000..100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
@@@ -1,413 -1,0 +1,409 @@@
 +/*
 + * 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.provisioning.java;
 +
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Set;
 +import org.apache.commons.collections4.CollectionUtils;
 +import org.apache.commons.collections4.Transformer;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.patch.PasswordPatch;
 +import org.apache.syncope.common.lib.patch.StatusPatch;
 +import org.apache.syncope.common.lib.patch.StringPatchItem;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.common.lib.to.PropagationStatus;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.PatchOperation;
 +import org.apache.syncope.core.persistence.api.dao.UserDAO;
 +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 +import org.apache.syncope.core.persistence.api.entity.user.User;
 +import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.common.lib.types.ResourceOperation;
 +import org.apache.syncope.common.lib.types.StatusPatchType;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 +import org.apache.syncope.core.provisioning.api.sync.ProvisioningResult;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 +import org.apache.syncope.core.workflow.api.UserWorkflowAdapter;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +
 +public class DefaultUserProvisioningManager implements UserProvisioningManager {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(UserProvisioningManager.class);
 +
 +    @Autowired
 +    protected UserWorkflowAdapter uwfAdapter;
 +
 +    @Autowired
 +    protected PropagationManager propagationManager;
 +
 +    @Autowired
 +    protected PropagationTaskExecutor taskExecutor;
 +
 +    @Autowired
 +    protected VirAttrHandler virtAttrHandler;
 +
 +    @Autowired
 +    protected UserDAO userDAO;
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> create(final UserTO userTO) {
 +        return create(userTO, true, false, null, Collections.<String>emptySet());
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> create(final UserTO userTO, final boolean storePassword) {
 +        return create(userTO, storePassword, false, null, Collections.<String>emptySet());
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> create(final UserTO userTO, final Set<String> excludedResources) {
 +        return create(userTO, false, false, null, excludedResources);
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> create(final UserTO userTO, final boolean storePassword,
 +            final boolean disablePwdPolicyCheck, final Boolean enabled, final Set<String> excludedResources) {
 +
 +        WorkflowResult<Pair<Long, Boolean>> created =
 +                uwfAdapter.create(userTO, disablePwdPolicyCheck, enabled, storePassword);
 +
 +        List<PropagationTask> tasks = propagationManager.getUserCreateTasks(
 +                created.getResult().getKey(),
 +                userTO.getPassword(),
 +                created.getResult().getValue(),
 +                created.getPropByRes(),
 +                userTO.getVirAttrs(),
 +                excludedResources);
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        return new ImmutablePair<>(created.getResult().getKey(), propagationReporter.getStatuses());
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> update(final UserPatch userPatch) {
 +        WorkflowResult<Pair<UserPatch, Boolean>> updated = uwfAdapter.update(userPatch);
 +
-         List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(updated);
-         if (tasks.isEmpty()) {
-             // SYNCOPE-459: take care of user virtual attributes ...
-             PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                     updated.getResult().getKey().getKey(),
-                     AnyTypeKind.USER,
-                     userPatch.getVirAttrs());
-             if (!propByResVirAttr.isEmpty()) {
-                 tasks.addAll(propagationManager.getUserUpdateTasks(updated, false, null));
-             }
++        // SYNCOPE-459: take care of user virtual attributes ...
++        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
++                updated.getResult().getKey().getKey(),
++                AnyTypeKind.USER,
++                userPatch.getVirAttrs());
++        if (updated.getPropByRes() == null) {
++            updated.setPropByRes(propByResVirAttr);
++        } else {
++            updated.getPropByRes().merge(propByResVirAttr);
 +        }
++
++        List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(updated);
++
 +        PropagationReporter propagationReporter = ApplicationContextProvider.getBeanFactory().
 +                getBean(PropagationReporter.class);
 +        if (!tasks.isEmpty()) {
 +            try {
 +                taskExecutor.execute(tasks, propagationReporter);
 +            } catch (PropagationException e) {
 +                LOG.error("Error propagation primary resource", e);
 +                propagationReporter.onPrimaryResourceFailure(tasks);
 +            }
 +        }
 +
 +        return new ImmutablePair<>(updated.getResult().getKey().getKey(), propagationReporter.getStatuses());
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> update(final UserPatch userPatch, final Set<String> excludedResources) {
 +        return update(userPatch, userPatch.getKey(), new ProvisioningResult(), null, excludedResources);
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> update(final UserPatch userPatch, final Long key,
 +            final ProvisioningResult result, final Boolean enabled, final Set<String> excludedResources) {
 +
 +        WorkflowResult<Pair<UserPatch, Boolean>> updated;
 +        try {
 +            updated = uwfAdapter.update(userPatch);
 +        } catch (Exception e) {
 +            LOG.error("Update of user {} failed, trying to sync its status anyway (if configured)", key, e);
 +
 +            result.setStatus(ProvisioningResult.Status.FAILURE);
 +            result.setMessage("Update failed, trying to sync status anyway (if configured)\n" + e.getMessage());
 +
 +            updated = new WorkflowResult<Pair<UserPatch, Boolean>>(
 +                    new ImmutablePair<>(userPatch, false), new PropagationByResource(),
 +                    new HashSet<String>());
 +        }
 +
 +        if (enabled != null) {
 +            User user = userDAO.find(key);
 +
 +            WorkflowResult<Long> enableUpdate = null;
 +            if (user.isSuspended() == null) {
 +                enableUpdate = uwfAdapter.activate(key, null);
 +            } else if (enabled && user.isSuspended()) {
 +                enableUpdate = uwfAdapter.reactivate(key);
 +            } else if (!enabled && !user.isSuspended()) {
 +                enableUpdate = uwfAdapter.suspend(key);
 +            }
 +
 +            if (enableUpdate != null) {
 +                if (enableUpdate.getPropByRes() != null) {
 +                    updated.getPropByRes().merge(enableUpdate.getPropByRes());
 +                    updated.getPropByRes().purge();
 +                }
 +                updated.getPerformedTasks().addAll(enableUpdate.getPerformedTasks());
 +            }
 +        }
 +
 +        List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
 +                updated, updated.getResult().getKey().getPassword() != null, excludedResources);
 +        PropagationReporter propagationReporter = ApplicationContextProvider.getBeanFactory().
 +                getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        return new ImmutablePair<>(updated.getResult().getKey().getKey(), propagationReporter.getStatuses());
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> delete(final Long key) {
 +        return delete(key, Collections.<String>emptySet());
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> delete(final Long key, final Set<String> excludedResources) {
 +        PropagationByResource propByRes = new PropagationByResource();
 +        propByRes.set(ResourceOperation.DELETE, userDAO.findAllResourceNames(userDAO.authFind(key)));
 +
 +        // Note here that we can only notify about "delete", not any other
 +        // task defined in workflow process definition: this because this
 +        // information could only be available after uwfAdapter.delete(), which
 +        // will also effectively remove user from db, thus making virtually
 +        // impossible by NotificationManager to fetch required user information
 +        List<PropagationTask> tasks = propagationManager.getDeleteTasks(
 +                AnyTypeKind.USER,
 +                key,
 +                propByRes,
 +                excludedResources);
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        try {
 +            uwfAdapter.delete(key);
 +        } catch (PropagationException e) {
 +            throw e;
 +        }
 +
 +        return propagationReporter.getStatuses();
 +    }
 +
 +    @Override
 +    public Long unlink(final UserPatch userPatch) {
 +        WorkflowResult<Pair<UserPatch, Boolean>> updated = uwfAdapter.update(userPatch);
 +        return updated.getResult().getKey().getKey();
 +    }
 +
 +    @Override
 +    public Long link(final UserPatch userPatch) {
 +        return uwfAdapter.update(userPatch).getResult().getKey().getKey();
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> activate(final StatusPatch statusPatch) {
 +        WorkflowResult<Long> updated = statusPatch.isOnSyncope()
 +                ? uwfAdapter.activate(statusPatch.getKey(), statusPatch.getToken())
 +                : new WorkflowResult<>(statusPatch.getKey(), null, statusPatch.getType().name().toLowerCase());
 +
 +        return new ImmutablePair<>(updated.getResult(), propagateStatus(statusPatch));
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> reactivate(final StatusPatch statusPatch) {
 +        WorkflowResult<Long> updated = statusPatch.isOnSyncope()
 +                ? uwfAdapter.reactivate(statusPatch.getKey())
 +                : new WorkflowResult<>(statusPatch.getKey(), null, statusPatch.getType().name().toLowerCase());
 +
 +        return new ImmutablePair<>(updated.getResult(), propagateStatus(statusPatch));
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> suspend(final StatusPatch statusPatch) {
 +        WorkflowResult<Long> updated = statusPatch.isOnSyncope()
 +                ? uwfAdapter.suspend(statusPatch.getKey())
 +                : new WorkflowResult<>(statusPatch.getKey(), null, statusPatch.getType().name().toLowerCase());
 +
 +        return new ImmutablePair<>(updated.getResult(), propagateStatus(statusPatch));
 +    }
 +
 +    protected List<PropagationStatus> propagateStatus(final StatusPatch statusPatch) {
-         Collection<String> noPropResourceNames = CollectionUtils.removeAll(
-                 userDAO.findAllResourceNames(userDAO.find(statusPatch.getKey())), statusPatch.getResources());
- 
++        PropagationByResource propByRes = new PropagationByResource();
++        propByRes.addAll(ResourceOperation.UPDATE, statusPatch.getResources());
 +        List<PropagationTask> tasks = propagationManager.getUpdateTasks(
 +                AnyTypeKind.USER,
 +                statusPatch.getKey(),
 +                false,
 +                statusPatch.getType() != StatusPatchType.SUSPEND,
++                propByRes,
 +                null,
-                 null,
-                 noPropResourceNames);
++                null);
++
 +        PropagationReporter propReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        return propReporter.getStatuses();
 +
 +    }
 +
 +    @Override
 +    public void internalSuspend(final Long key) {
 +        Pair<WorkflowResult<Long>, Boolean> updated = uwfAdapter.internalSuspend(key);
 +
 +        // propagate suspension if and only if it is required by policy
 +        if (updated != null && updated.getValue()) {
 +            UserPatch userPatch = new UserPatch();
 +            userPatch.setKey(updated.getKey().getResult());
 +
 +            List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
 +                    new WorkflowResult<Pair<UserPatch, Boolean>>(
 +                            new ImmutablePair<>(userPatch, Boolean.FALSE),
 +                            updated.getKey().getPropByRes(), updated.getKey().getPerformedTasks()));
 +            taskExecutor.execute(tasks);
 +        }
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> provision(
 +            final Long key, final boolean changePwd, final String password, final Collection<String> resources) {
 +
 +        UserPatch userPatch = new UserPatch();
 +        userPatch.setKey(key);
 +        userPatch.getResources().addAll(CollectionUtils.collect(resources,
 +                new Transformer<String, StringPatchItem>() {
 +
 +                    @Override
 +                    public StringPatchItem transform(final String input) {
 +                        return new StringPatchItem.Builder().operation(PatchOperation.ADD_REPLACE).value(input).build();
 +                    }
 +                }, new HashSet<StringPatchItem>()));
 +
 +        if (changePwd) {
 +            PasswordPatch passwordPatch = new PasswordPatch();
 +            passwordPatch.setOnSyncope(false);
 +            passwordPatch.getResources().addAll(resources);
 +            passwordPatch.setValue(password);
 +            userPatch.setPassword(passwordPatch);
 +        }
 +
 +        PropagationByResource propByRes = new PropagationByResource();
 +        propByRes.addAll(ResourceOperation.UPDATE, resources);
 +
 +        WorkflowResult<Pair<UserPatch, Boolean>> wfResult = new WorkflowResult<Pair<UserPatch, Boolean>>(
 +                ImmutablePair.of(userPatch, (Boolean) null), propByRes, "update");
 +
 +        List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(wfResult, changePwd, null);
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        return propagationReporter.getStatuses();
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> deprovision(final Long key, final Collection<String> resources) {
 +        PropagationByResource propByRes = new PropagationByResource();
 +        propByRes.set(ResourceOperation.DELETE, resources);
 +
 +        List<PropagationTask> tasks = propagationManager.getDeleteTasks(
 +                AnyTypeKind.USER,
 +                key,
 +                propByRes,
 +                CollectionUtils.removeAll(userDAO.findAllResourceNames(userDAO.authFind(key)), resources));
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        return propagationReporter.getStatuses();
 +    }
 +
 +    @Override
 +    public void requestPasswordReset(final Long key) {
 +        uwfAdapter.requestPasswordReset(key);
 +    }
 +
 +    @Override
 +    public void confirmPasswordReset(final Long key, final String token, final String password) {
-         uwfAdapter.confirmPasswordReset(key, token, password);
++        WorkflowResult<Pair<UserPatch, Boolean>> updated = uwfAdapter.confirmPasswordReset(key, token, password);
 +
-         UserPatch userPatch = new UserPatch();
-         userPatch.setKey(key);
-         userPatch.setPassword(new PasswordPatch.Builder().value(password).build());
++        List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(updated);
 +
-         List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
-                 new WorkflowResult<Pair<UserPatch, Boolean>>(
-                         new ImmutablePair<UserPatch, Boolean>(userPatch, null), null, "confirmPasswordReset"),
-                 true, null);
 +        PropagationReporter propReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propReporter.onPrimaryResourceFailure(tasks);
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --cc core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index 82dfbc0,0000000..3420d27
mode 100644,000000..100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@@ -1,499 -1,0 +1,502 @@@
 +/*
 + * 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.provisioning.java.data;
 +
 +import java.util.Collection;
 +import java.util.Date;
 +import java.util.HashSet;
 +import java.util.Map;
 +import java.util.Set;
 +import javax.annotation.Resource;
 +import org.apache.commons.collections4.CollectionUtils;
 +import org.apache.commons.collections4.Predicate;
 +import org.apache.commons.collections4.Transformer;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.patch.LongPatchItem;
 +import org.apache.syncope.common.lib.patch.MembershipPatch;
 +import org.apache.syncope.common.lib.patch.PasswordPatch;
 +import org.apache.syncope.common.lib.patch.RelationshipPatch;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.common.lib.to.MembershipTO;
 +import org.apache.syncope.common.lib.to.RelationshipTO;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.CipherAlgorithm;
 +import org.apache.syncope.common.lib.types.ClientExceptionType;
 +import org.apache.syncope.common.lib.types.PatchOperation;
 +import org.apache.syncope.common.lib.types.ResourceOperation;
 +import org.apache.syncope.core.persistence.api.dao.ConfDAO;
 +import org.apache.syncope.core.persistence.api.dao.SecurityQuestionDAO;
 +import org.apache.syncope.core.persistence.api.entity.group.Group;
 +import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
 +import org.apache.syncope.core.persistence.api.entity.user.User;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 +import org.apache.syncope.core.misc.security.AuthContextUtils;
 +import org.apache.syncope.core.misc.security.Encryptor;
 +import org.apache.syncope.core.misc.spring.BeanUtils;
 +import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 +import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 +import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 +import org.apache.syncope.core.persistence.api.entity.Role;
 +import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 +import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 +import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 +import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 +import org.apache.syncope.core.persistence.api.entity.user.UMembership;
 +import org.apache.syncope.core.persistence.api.entity.user.URelationship;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.stereotype.Component;
 +import org.springframework.transaction.annotation.Transactional;
 +
 +@Component
 +@Transactional(rollbackFor = { Throwable.class })
 +public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDataBinder {
 +
 +    private static final String[] IGNORE_PROPERTIES = {
 +        "type", "realm", "auxClasses", "roles", "dynRoles", "relationships", "memberships", "dynGroups",
 +        "plainAttrs", "derAttrs", "virAttrs", "resources", "securityQuestion", "securityAnswer"
 +    };
 +
 +    @Autowired
 +    private RoleDAO roleDAO;
 +
 +    @Autowired
 +    private ConfDAO confDAO;
 +
 +    @Autowired
 +    private SecurityQuestionDAO securityQuestionDAO;
 +
 +    @Autowired
 +    private AnyTypeDAO anyTypeDAO;
 +
 +    @Resource(name = "adminUser")
 +    private String adminUser;
 +
 +    @Resource(name = "anonymousUser")
 +    private String anonymousUser;
 +
 +    private final Encryptor encryptor = Encryptor.getInstance();
 +
 +    @Transactional(readOnly = true)
 +    @Override
 +    public UserTO getAuthenticatedUserTO() {
 +        final UserTO authUserTO;
 +
 +        String authUsername = AuthContextUtils.getUsername();
 +        if (anonymousUser.equals(authUsername)) {
 +            authUserTO = new UserTO();
 +            authUserTO.setKey(-2);
 +            authUserTO.setUsername(anonymousUser);
 +        } else if (adminUser.equals(authUsername)) {
 +            authUserTO = new UserTO();
 +            authUserTO.setKey(-1);
 +            authUserTO.setUsername(adminUser);
 +        } else {
 +            User authUser = userDAO.find(authUsername);
 +            authUserTO = getUserTO(authUser, true);
 +        }
 +
 +        return authUserTO;
 +    }
 +
 +    @Transactional(readOnly = true)
 +    @Override
 +    public boolean verifyPassword(final String username, final String password) {
 +        return verifyPassword(userDAO.authFind(username), password);
 +    }
 +
 +    @Transactional(readOnly = true)
 +    @Override
 +    public boolean verifyPassword(final User user, final String password) {
 +        return encryptor.verify(password, user.getCipherAlgorithm(), user.getPassword());
 +    }
 +
 +    private void setPassword(final User user, final String password, final SyncopeClientCompositeException scce) {
 +        try {
 +            String algorithm = confDAO.find(
 +                    "password.cipher.algorithm", CipherAlgorithm.AES.name()).getValues().get(0).getStringValue();
 +            CipherAlgorithm predefined = CipherAlgorithm.valueOf(algorithm);
 +            user.setPassword(password, predefined);
 +        } catch (IllegalArgumentException e) {
 +            final SyncopeClientException invalidCiperAlgorithm =
 +                    SyncopeClientException.build(ClientExceptionType.NotFound);
 +            invalidCiperAlgorithm.getElements().add(e.getMessage());
 +            scce.addException(invalidCiperAlgorithm);
 +
 +            throw scce;
 +        }
 +    }
 +
 +    @Override
 +    public void create(final User user, final UserTO userTO, final boolean storePassword) {
 +        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
 +
 +        // roles
 +        for (Long roleKey : userTO.getRoles()) {
 +            Role role = roleDAO.find(roleKey);
 +            if (role == null) {
 +                LOG.warn("Ignoring unknown role with id {}", roleKey);
 +            } else {
 +                user.add(role);
 +            }
 +        }
 +
 +        // relationships
 +        for (RelationshipTO relationshipTO : userTO.getRelationships()) {
 +            AnyObject anyObject = anyObjectDAO.find(relationshipTO.getRightKey());
 +            if (anyObject == null) {
 +                LOG.debug("Ignoring invalid anyObject " + relationshipTO.getRightKey());
 +            } else {
 +                RelationshipType relationshipType = relationshipTypeDAO.find(relationshipTO.getType());
 +                URelationship relationship = null;
 +                if (user.getKey() != null) {
 +                    relationship = user.getRelationship(relationshipType, anyObject.getKey());
 +                }
 +                if (relationship == null) {
 +                    relationship = entityFactory.newEntity(URelationship.class);
 +                    relationship.setType(relationshipType);
 +                    relationship.setRightEnd(anyObject);
 +                    relationship.setLeftEnd(user);
 +
 +                    user.add(relationship);
 +                }
 +            }
 +        }
 +
 +        // memberships
 +        for (MembershipTO membershipTO : userTO.getMemberships()) {
 +            Group group = groupDAO.find(membershipTO.getRightKey());
 +
 +            if (group == null) {
 +                LOG.debug("Ignoring invalid group " + membershipTO.getGroupName());
 +            } else {
 +                UMembership membership = null;
 +                if (user.getKey() != null) {
 +                    membership = user.getMembership(group.getKey());
 +                }
 +                if (membership == null) {
 +                    membership = entityFactory.newEntity(UMembership.class);
 +                    membership.setRightEnd(group);
 +                    membership.setLeftEnd(user);
 +
 +                    user.add(membership);
 +                }
 +            }
 +        }
 +
 +        // realm, attributes, derived attributes, virtual attributes and resources
 +        fill(user, userTO, anyUtilsFactory.getInstance(AnyTypeKind.USER), scce);
 +
 +        // set password
 +        if (StringUtils.isBlank(userTO.getPassword()) || !storePassword) {
 +            LOG.debug("Password was not provided or not required to be stored");
 +        } else {
 +            setPassword(user, userTO.getPassword(), scce);
 +        }
 +
 +        // set username
 +        user.setUsername(userTO.getUsername());
 +
 +        // security question / answer
 +        if (userTO.getSecurityQuestion() != null) {
 +            SecurityQuestion securityQuestion = securityQuestionDAO.find(userTO.getSecurityQuestion());
 +            if (securityQuestion != null) {
 +                user.setSecurityQuestion(securityQuestion);
 +            }
 +        }
 +        user.setSecurityAnswer(userTO.getSecurityAnswer());
 +
 +        user.setMustChangePassword(userTO.isMustChangePassword());
 +    }
 +
 +    private boolean isPasswordMapped(final ExternalResource resource) {
 +        boolean result = false;
 +
 +        Provision provision = resource.getProvision(anyTypeDAO.findUser());
 +        if (provision != null && provision.getMapping() != null) {
 +            result = CollectionUtils.exists(provision.getMapping().getItems(), new Predicate<MappingItem>() {
 +
 +                @Override
 +                public boolean evaluate(final MappingItem item) {
 +                    return item.isPassword();
 +                }
 +            });
 +        }
 +
 +        return result;
 +    }
 +
 +    @Override
 +    public PropagationByResource update(final User toBeUpdated, final UserPatch userPatch) {
 +        // Re-merge any pending change from workflow tasks
 +        final User user = userDAO.save(toBeUpdated);
 +
 +        PropagationByResource propByRes = new PropagationByResource();
 +
 +        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
 +
 +        Collection<String> currentResources = userDAO.findAllResourceNames(user);
 +
 +        // fetch connObjectKeys before update
 +        Map<String, String> oldConnObjectKeys = getConnObjectKeys(user);
 +
 +        // realm
 +        setRealm(user, userPatch);
 +
 +        // password
 +        if (userPatch.getPassword() != null && StringUtils.isNotBlank(userPatch.getPassword().getValue())) {
-             setPassword(user, userPatch.getPassword().getValue(), scce);
-             user.setChangePwdDate(new Date());
-             propByRes.addAll(ResourceOperation.UPDATE, currentResources);
++            if (userPatch.getPassword().isOnSyncope()) {
++                setPassword(user, userPatch.getPassword().getValue(), scce);
++                user.setChangePwdDate(new Date());
++            }
++
++            propByRes.addAll(ResourceOperation.UPDATE, userPatch.getPassword().getResources());
 +        }
 +
 +        // username
 +        if (userPatch.getUsername() != null && StringUtils.isNotBlank(userPatch.getUsername().getValue())) {
-             propByRes.addAll(ResourceOperation.UPDATE, currentResources);
- 
 +            String oldUsername = user.getUsername();
 +            user.setUsername(userPatch.getUsername().getValue());
 +
 +            if (oldUsername.equals(AuthContextUtils.getUsername())) {
 +                AuthContextUtils.updateUsername(userPatch.getUsername().getValue());
 +            }
++
++            propByRes.addAll(ResourceOperation.UPDATE, currentResources);
 +        }
 +
 +        // security question / answer:
 +        if (userPatch.getSecurityQuestion() != null) {
 +            if (userPatch.getSecurityQuestion().getValue() == null) {
 +                user.setSecurityQuestion(null);
 +                user.setSecurityAnswer(null);
 +            } else {
 +                SecurityQuestion securityQuestion =
 +                        securityQuestionDAO.find(userPatch.getSecurityQuestion().getValue());
 +                if (securityQuestion != null) {
 +                    user.setSecurityQuestion(securityQuestion);
 +                    user.setSecurityAnswer(userPatch.getSecurityAnswer().getValue());
 +                }
 +            }
 +        }
 +
 +        if (userPatch.getMustChangePassword() != null) {
 +            user.setMustChangePassword(userPatch.getMustChangePassword().getValue());
 +        }
 +
 +        // roles
 +        for (LongPatchItem patch : userPatch.getRoles()) {
 +            Role role = roleDAO.find(patch.getValue());
 +            if (role == null) {
 +                LOG.warn("Ignoring unknown role with key {}", patch.getValue());
 +            } else {
 +                switch (patch.getOperation()) {
 +                    case ADD_REPLACE:
 +                        user.add(role);
 +                        break;
 +
 +                    case DELETE:
 +                    default:
 +                        user.remove(role);
 +                }
 +            }
 +        }
 +
 +        // attributes, derived attributes, virtual attributes and resources
 +        propByRes.merge(fill(user, userPatch, anyUtilsFactory.getInstance(AnyTypeKind.USER), scce));
 +
 +        Set<String> toBeDeprovisioned = new HashSet<>();
 +        Set<String> toBeProvisioned = new HashSet<>();
 +
 +        // relationships
 +        for (RelationshipPatch patch : userPatch.getRelationships()) {
 +            if (patch.getRelationshipTO() != null) {
 +                RelationshipType relationshipType = relationshipTypeDAO.find(patch.getRelationshipTO().getType());
 +                URelationship relationship =
 +                        user.getRelationship(relationshipType, patch.getRelationshipTO().getRightKey());
 +                if (relationship != null) {
 +                    user.remove(relationship);
 +                    toBeDeprovisioned.addAll(relationship.getRightEnd().getResourceNames());
 +                }
 +
 +                if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
 +                    AnyObject otherEnd = anyObjectDAO.find(patch.getRelationshipTO().getRightKey());
 +                    if (otherEnd == null) {
 +                        LOG.debug("Ignoring invalid any object {}", patch.getRelationshipTO().getRightKey());
 +                    } else {
 +
 +                        relationship = entityFactory.newEntity(URelationship.class);
 +                        relationship.setType(relationshipType);
 +                        relationship.setRightEnd(otherEnd);
 +                        relationship.setLeftEnd(user);
 +
 +                        user.add(relationship);
 +
 +                        toBeProvisioned.addAll(otherEnd.getResourceNames());
 +                    }
 +                }
 +            }
 +        }
 +
 +        // memberships
 +        for (MembershipPatch patch : userPatch.getMemberships()) {
 +            if (patch.getMembershipTO() != null) {
 +                UMembership membership = user.getMembership(patch.getMembershipTO().getRightKey());
 +                if (membership != null) {
 +                    user.remove(membership);
 +                    toBeDeprovisioned.addAll(membership.getRightEnd().getResourceNames());
 +                }
 +
 +                if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
 +                    Group group = groupDAO.find(patch.getMembershipTO().getRightKey());
 +                    if (group == null) {
 +                        LOG.debug("Ignoring invalid group {}", patch.getMembershipTO().getRightKey());
 +                    } else {
 +                        membership = entityFactory.newEntity(UMembership.class);
 +                        membership.setRightEnd(group);
 +                        membership.setLeftEnd(user);
 +
 +                        user.add(membership);
 +
 +                        toBeProvisioned.addAll(group.getResourceNames());
 +
 +                        // SYNCOPE-686: if password is invertible and we are adding resources with password mapping,
 +                        // ensure that they are counted for password propagation
 +                        if (toBeUpdated.canDecodePassword()) {
 +                            if (userPatch.getPassword() == null) {
 +                                userPatch.setPassword(new PasswordPatch());
 +                            }
 +                            for (ExternalResource resource : group.getResources()) {
 +                                if (isPasswordMapped(resource)) {
 +                                    userPatch.getPassword().getResources().add(resource.getKey());
 +                                }
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +        propByRes.addAll(ResourceOperation.DELETE, toBeDeprovisioned);
 +        propByRes.addAll(ResourceOperation.UPDATE, toBeProvisioned);
 +
 +        // In case of new memberships all current resources need to be updated in order to propagate new group
 +        // attribute values.
 +        if (!toBeDeprovisioned.isEmpty() || !toBeProvisioned.isEmpty()) {
 +            currentResources.removeAll(toBeDeprovisioned);
 +            propByRes.addAll(ResourceOperation.UPDATE, currentResources);
 +        }
 +
 +        // check if some connObjectKey was changed by the update above
 +        Map<String, String> newcCnnObjectKeys = getConnObjectKeys(user);
 +        for (Map.Entry<String, String> entry : oldConnObjectKeys.entrySet()) {
 +            if (newcCnnObjectKeys.containsKey(entry.getKey())
 +                    && !entry.getValue().equals(newcCnnObjectKeys.get(entry.getKey()))) {
 +
 +                propByRes.addOldConnObjectKey(entry.getKey(), entry.getValue());
 +                propByRes.add(ResourceOperation.UPDATE, entry.getKey());
 +            }
 +        }
 +
 +        return propByRes;
 +    }
 +
 +    @Transactional(readOnly = true)
 +    @Override
 +    public UserTO getUserTO(final User user, final boolean details) {
 +        UserTO userTO = new UserTO();
 +
 +        BeanUtils.copyProperties(user, userTO, IGNORE_PROPERTIES);
 +
 +        if (user.getSecurityQuestion() != null) {
 +            userTO.setSecurityQuestion(user.getSecurityQuestion().getKey());
 +        }
 +
 +        if (details) {
 +            virAttrHander.retrieveVirAttrValues(user);
 +        }
 +
 +        fillTO(userTO, user.getRealm().getFullPath(), user.getAuxClasses(),
 +                user.getPlainAttrs(), user.getDerAttrs(), user.getVirAttrs(), userDAO.findAllResources(user));
 +
 +        if (details) {
 +            // roles
 +            CollectionUtils.collect(user.getRoles(), new Transformer<Role, Long>() {
 +
 +                @Override
 +                public Long transform(final Role role) {
 +                    return role.getKey();
 +                }
 +            }, userTO.getRoles());
 +
 +            // relationships
 +            CollectionUtils.collect(user.getRelationships(), new Transformer<URelationship, RelationshipTO>() {
 +
 +                @Override
 +                public RelationshipTO transform(final URelationship relationship) {
 +                    return UserDataBinderImpl.this.getRelationshipTO(relationship);
 +                }
 +
 +            }, userTO.getRelationships());
 +
 +            // memberships
 +            CollectionUtils.collect(user.getMemberships(), new Transformer<UMembership, MembershipTO>() {
 +
 +                @Override
 +                public MembershipTO transform(final UMembership membership) {
 +                    return UserDataBinderImpl.this.getMembershipTO(membership);
 +                }
 +            }, userTO.getMemberships());
 +
 +            // dynamic memberships
 +            CollectionUtils.collect(userDAO.findDynRoleMemberships(user), new Transformer<Role, Long>() {
 +
 +                @Override
 +                public Long transform(final Role role) {
 +                    return role.getKey();
 +                }
 +            }, userTO.getDynRoles());
 +            CollectionUtils.collect(userDAO.findDynGroupMemberships(user), new Transformer<Group, Long>() {
 +
 +                @Override
 +                public Long transform(final Group group) {
 +                    return group.getKey();
 +                }
 +            }, userTO.getDynGroups());
 +        }
 +
 +        return userTO;
 +    }
 +
 +    @Transactional(readOnly = true)
 +    @Override
 +    public UserTO getUserTO(final String username) {
 +        return getUserTO(userDAO.authFind(username), true);
 +    }
 +
 +    @Transactional(readOnly = true)
 +    @Override
 +    public UserTO getUserTO(final Long key) {
 +        return getUserTO(userDAO.authFind(key), true);
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
----------------------------------------------------------------------
diff --cc core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
index ebf9c99,0000000..0d15ffd
mode 100644,000000..100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
@@@ -1,426 -1,0 +1,420 @@@
 +/*
 + * 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.provisioning.java.propagation;
 +
 +import java.util.ArrayList;
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +import org.apache.commons.collections4.CollectionUtils;
 +import org.apache.commons.collections4.Transformer;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.patch.AttrPatch;
 +import org.apache.syncope.common.lib.patch.StringPatchItem;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.common.lib.to.AttrTO;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.common.lib.types.ResourceOperation;
 +import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 +import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 +import org.apache.syncope.core.persistence.api.dao.UserDAO;
 +import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 +import org.apache.syncope.core.persistence.api.entity.VirAttr;
 +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 +import org.apache.syncope.core.persistence.api.entity.user.User;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 +import org.apache.syncope.core.misc.ConnObjectUtils;
 +import org.apache.syncope.core.misc.MappingUtils;
 +import org.apache.syncope.core.misc.jexl.JexlUtils;
 +import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 +import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 +import org.apache.syncope.core.persistence.api.entity.Any;
 +import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 +import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 +import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 +import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 +import org.identityconnectors.framework.common.objects.Attribute;
 +import org.identityconnectors.framework.common.objects.AttributeBuilder;
 +import org.identityconnectors.framework.common.objects.AttributeUtil;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.transaction.annotation.Transactional;
 +
 +/**
 + * Manage the data propagation to external resources.
 + */
 +@Transactional(rollbackFor = { Throwable.class })
 +public class PropagationManagerImpl implements PropagationManager {
 +
 +    protected static final Logger LOG = LoggerFactory.getLogger(PropagationManager.class);
 +
 +    @Autowired
 +    protected AnyObjectDAO anyObjectDAO;
 +
 +    /**
 +     * User DAO.
 +     */
 +    @Autowired
 +    protected UserDAO userDAO;
 +
 +    /**
 +     * Group DAO.
 +     */
 +    @Autowired
 +    protected GroupDAO groupDAO;
 +
 +    /**
 +     * Resource DAO.
 +     */
 +    @Autowired
 +    protected ExternalResourceDAO resourceDAO;
 +
 +    @Autowired
 +    protected EntityFactory entityFactory;
 +
 +    /**
 +     * ConnObjectUtils.
 +     */
 +    @Autowired
 +    protected ConnObjectUtils connObjectUtils;
 +
 +    @Autowired
 +    protected VirAttrHandler virAttrHandler;
 +
 +    @Autowired
 +    protected MappingUtils mappingUtils;
 +
 +    protected Any<?, ?, ?> find(final AnyTypeKind kind, final Long key) {
 +        AnyDAO<? extends Any<?, ?, ?>> dao;
 +        switch (kind) {
 +            case ANY_OBJECT:
 +                dao = anyObjectDAO;
 +                break;
 +
 +            case GROUP:
 +                dao = groupDAO;
 +                break;
 +
 +            case USER:
 +            default:
 +                dao = userDAO;
 +        }
 +
 +        return dao.authFind(key);
 +    }
 +
 +    @Override
 +    public List<PropagationTask> getCreateTasks(
 +            final AnyTypeKind kind,
 +            final Long key,
 +            final PropagationByResource propByRes,
 +            final Collection<AttrTO> vAttrs,
 +            final Collection<String> noPropResourceNames) {
 +
 +        Any<?, ?, ?> any = find(kind, key);
 +        if (vAttrs != null && !vAttrs.isEmpty()) {
 +            virAttrHandler.createVirtual(any, vAttrs);
 +        }
 +
 +        return getCreateTasks(any, null, null, propByRes, noPropResourceNames);
 +    }
 +
 +    @Override
 +    public List<PropagationTask> getUserCreateTasks(
 +            final Long key,
 +            final String password,
 +            final Boolean enable,
 +            final PropagationByResource propByRes,
 +            final Collection<AttrTO> vAttrs,
 +            final Collection<String> noPropResourceNames) {
 +
 +        User user = userDAO.authFind(key);
 +        if (vAttrs != null && !vAttrs.isEmpty()) {
 +            virAttrHandler.createVirtual(user, vAttrs);
 +        }
 +
 +        return getCreateTasks(user, password, enable, propByRes, noPropResourceNames);
 +    }
 +
 +    protected List<PropagationTask> getCreateTasks(
 +            final Any<?, ?, ?> any,
 +            final String password,
 +            final Boolean enable,
 +            final PropagationByResource propByRes,
 +            final Collection<String> noPropResourceNames) {
 +
 +        if (propByRes == null || propByRes.isEmpty()) {
 +            return Collections.<PropagationTask>emptyList();
 +        }
 +
 +        if (noPropResourceNames != null) {
 +            propByRes.get(ResourceOperation.CREATE).removeAll(noPropResourceNames);
 +        }
 +
 +        return createTasks(any, password, true, null, enable, false, propByRes);
 +    }
 +
 +    @Override
 +    public List<PropagationTask> getUpdateTasks(
 +            final AnyTypeKind kind,
 +            final Long key,
 +            final boolean changePwd,
 +            final Boolean enable,
 +            final PropagationByResource propByRes,
 +            final Collection<AttrPatch> vAttrs,
 +            final Collection<String> noPropResourceNames) {
 +
 +        return getUpdateTasks(find(kind, key), null, changePwd, enable, propByRes, vAttrs, noPropResourceNames);
 +    }
 +
 +    @Override
 +    public List<PropagationTask> getUserUpdateTasks(
 +            final WorkflowResult<Pair<UserPatch, Boolean>> wfResult,
 +            final boolean changePwd,
 +            final Collection<String> noPropResourceNames) {
 +
 +        return getUpdateTasks(
 +                userDAO.authFind(wfResult.getResult().getKey().getKey()),
 +                wfResult.getResult().getKey().getPassword() == null
 +                        ? null
 +                        : wfResult.getResult().getKey().getPassword().getValue(),
 +                changePwd,
 +                wfResult.getResult().getValue(),
 +                wfResult.getPropByRes(),
 +                wfResult.getResult().getKey().getVirAttrs(),
 +                noPropResourceNames);
 +    }
 +
 +    @Override
 +    public List<PropagationTask> getUserUpdateTasks(final WorkflowResult<Pair<UserPatch, Boolean>> wfResult) {
 +        UserPatch userPatch = wfResult.getResult().getKey();
 +
 +        // Propagate password update only to requested resources
 +        List<PropagationTask> tasks = new ArrayList<>();
 +        if (userPatch.getPassword() == null) {
 +            // a. no specific password propagation request: generate propagation tasks for any resource associated
 +            tasks = getUserUpdateTasks(wfResult, false, null);
 +        } else {
 +            // b. generate the propagation task list in two phases: first the ones containing password,
 +            // the the rest (with no password)
 +            PropagationByResource origPropByRes = new PropagationByResource();
 +            origPropByRes.merge(wfResult.getPropByRes());
 +
 +            Set<String> pwdResourceNames = new HashSet<>(userPatch.getPassword().getResources());
 +            Collection<String> currentResourceNames =
 +                    userDAO.findAllResourceNames(userDAO.authFind(userPatch.getKey()));
 +            pwdResourceNames.retainAll(currentResourceNames);
 +            PropagationByResource pwdPropByRes = new PropagationByResource();
 +            pwdPropByRes.addAll(ResourceOperation.UPDATE, pwdResourceNames);
 +            if (!pwdPropByRes.isEmpty()) {
 +                Set<String> toBeExcluded = new HashSet<>(currentResourceNames);
 +                toBeExcluded.addAll(CollectionUtils.collect(userPatch.getResources(),
 +                        new Transformer<StringPatchItem, String>() {
 +
 +                            @Override
 +                            public String transform(final StringPatchItem input) {
 +                                return input.getValue();
 +                            }
 +                        }));
 +                toBeExcluded.removeAll(pwdResourceNames);
 +                tasks.addAll(getUserUpdateTasks(wfResult, true, toBeExcluded));
 +            }
 +
 +            PropagationByResource nonPwdPropByRes = new PropagationByResource();
 +            nonPwdPropByRes.merge(origPropByRes);
 +            nonPwdPropByRes.removeAll(pwdResourceNames);
 +            nonPwdPropByRes.purge();
 +            if (!nonPwdPropByRes.isEmpty()) {
 +                tasks.addAll(getUserUpdateTasks(wfResult, false, pwdResourceNames));
 +            }
 +        }
 +
 +        return tasks;
 +    }
 +
 +    protected List<PropagationTask> getUpdateTasks(
 +            final Any<?, ?, ?> any,
 +            final String password,
 +            final boolean changePwd,
 +            final Boolean enable,
 +            final PropagationByResource propByRes,
 +            final Collection<AttrPatch> vAttrs,
 +            final Collection<String> noPropResourceNames) {
 +
 +        PropagationByResource localPropByRes = virAttrHandler.updateVirtual(
 +                any,
 +                vAttrs == null ? Collections.<AttrPatch>emptySet() : vAttrs);
- 
-         if (propByRes == null || propByRes.isEmpty()) {
-             localPropByRes.addAll(ResourceOperation.UPDATE, any.getResourceNames());
-         } else {
-             localPropByRes.merge(propByRes);
-         }
- 
++        localPropByRes.merge(propByRes);
 +        if (noPropResourceNames != null) {
 +            localPropByRes.removeAll(noPropResourceNames);
 +        }
 +
 +        Map<String, AttrPatch> vAttrsMap = null;
 +        if (vAttrs != null) {
 +            vAttrsMap = new HashMap<>();
 +            for (AttrPatch attrPatch : vAttrs) {
 +                vAttrsMap.put(attrPatch.getAttrTO().getSchema(), attrPatch);
 +            }
 +        }
 +
 +        return createTasks(any, password, changePwd, vAttrsMap, enable, false, localPropByRes);
 +    }
 +
 +    @Override
 +    public List<PropagationTask> getDeleteTasks(
 +            final AnyTypeKind kind,
 +            final Long key,
 +            final PropagationByResource propByRes,
 +            final Collection<String> noPropResourceNames) {
 +
 +        Any<?, ?, ?> any = find(kind, key);
 +
 +        PropagationByResource localPropByRes = new PropagationByResource();
 +
 +        if (propByRes == null || propByRes.isEmpty()) {
 +            localPropByRes.addAll(ResourceOperation.DELETE, any.getResourceNames());
 +        } else {
 +            localPropByRes.merge(propByRes);
 +        }
 +
 +        if (noPropResourceNames != null) {
 +            localPropByRes.removeAll(noPropResourceNames);
 +        }
 +
 +        return getDeleteTasks(any, localPropByRes, noPropResourceNames);
 +    }
 +
 +    protected List<PropagationTask> getDeleteTasks(
 +            final Any<?, ?, ?> any,
 +            final PropagationByResource propByRes,
 +            final Collection<String> noPropResourceNames) {
 +
 +        return createTasks(any, null, false, null, false, true, propByRes);
 +    }
 +
 +    /**
 +     * Create propagation tasks.
 +     *
 +     * @param any user / group to be provisioned
 +     * @param password cleartext password to be provisioned
 +     * @param changePwd whether password should be included for propagation attributes or not
 +     * @param vAttrs virtual attributes to be maaged
 +     * @param enable whether user must be enabled or not
 +     * @param deleteOnResource whether user / group must be deleted anyway from external resource or not
 +     * @param propByRes operation to be performed per resource
 +     * @return list of propagation tasks created
 +     */
 +    protected List<PropagationTask> createTasks(final Any<?, ?, ?> any,
 +            final String password, final boolean changePwd,
 +            final Map<String, AttrPatch> vAttrs,
 +            final Boolean enable, final boolean deleteOnResource, final PropagationByResource propByRes) {
 +
 +        LOG.debug("Provisioning any {}:\n{}", any, propByRes);
 +
 +        if (!propByRes.get(ResourceOperation.CREATE).isEmpty() && vAttrs != null) {
 +            virAttrHandler.retrieveVirAttrValues(any);
 +
 +            // update vAttrsToBeUpdated as well
 +            for (VirAttr<?> virAttr : any.getVirAttrs()) {
 +                String schema = virAttr.getSchema().getKey();
 +
 +                vAttrs.put(schema, new AttrPatch.Builder().
 +                        attrTO(new AttrTO.Builder().schema(schema).values(virAttr.getValues()).build()).
 +                        build());
 +            }
 +        }
 +
 +        // Avoid duplicates - see javadoc
 +        propByRes.purge();
 +        LOG.debug("After purge: {}", propByRes);
 +
 +        List<PropagationTask> tasks = new ArrayList<>();
 +
 +        for (ResourceOperation operation : ResourceOperation.values()) {
 +            for (String resourceName : propByRes.get(operation)) {
 +                ExternalResource resource = resourceDAO.find(resourceName);
 +                Provision provision = resource == null ? null : resource.getProvision(any.getType());
 +                if (resource == null) {
 +                    LOG.error("Invalid resource name specified: {}, ignoring...", resourceName);
 +                } else if (provision == null) {
 +                    LOG.error("No provision specified on resource {} for type {}, ignoring...",
 +                            resource, any.getType());
 +                } else if (MappingUtils.getPropagationMappingItems(provision).isEmpty()) {
 +                    LOG.warn("Requesting propagation for {} but no propagation mapping provided for {}",
 +                            any.getType(), resource);
 +                } else {
 +                    PropagationTask task = entityFactory.newEntity(PropagationTask.class);
 +                    task.setResource(resource);
 +                    task.setObjectClassName(
 +                            resource.getProvision(any.getType()).getObjectClass().getObjectClassValue());
 +                    task.setAnyTypeKind(any.getType().getKind());
 +                    if (!deleteOnResource) {
 +                        task.setAnyKey(any.getKey());
 +                    }
 +                    task.setOperation(operation);
 +                    task.setOldConnObjectKey(propByRes.getOldConnObjectKey(resource.getKey()));
 +
 +                    Pair<String, Set<Attribute>> preparedAttrs = mappingUtils.prepareAttrs(
 +                            any, password, changePwd, vAttrs, enable, provision);
 +                    task.setConnObjectKey(preparedAttrs.getKey());
 +
 +                    // Check if any of mandatory attributes (in the mapping) is missing or not received any value: 
 +                    // if so, add special attributes that will be evaluated by PropagationTaskExecutor
 +                    List<String> mandatoryMissing = new ArrayList<>();
 +                    List<String> mandatoryNullOrEmpty = new ArrayList<>();
 +                    for (MappingItem item : MappingUtils.getPropagationMappingItems(provision)) {
 +                        if (!item.isConnObjectKey()
 +                                && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) {
 +
 +                            Attribute attr = AttributeUtil.find(item.getExtAttrName(), preparedAttrs.getValue());
 +                            if (attr == null) {
 +                                mandatoryMissing.add(item.getExtAttrName());
 +                            } else if (attr.getValue() == null || attr.getValue().isEmpty()) {
 +                                mandatoryNullOrEmpty.add(item.getExtAttrName());
 +                            }
 +                        }
 +                    }
 +                    if (!mandatoryMissing.isEmpty()) {
 +                        preparedAttrs.getValue().add(AttributeBuilder.build(
 +                                PropagationTaskExecutor.MANDATORY_MISSING_ATTR_NAME, mandatoryMissing));
 +                    }
 +                    if (!mandatoryNullOrEmpty.isEmpty()) {
 +                        preparedAttrs.getValue().add(AttributeBuilder.build(
 +                                PropagationTaskExecutor.MANDATORY_NULL_OR_EMPTY_ATTR_NAME, mandatoryNullOrEmpty));
 +                    }
 +
 +                    task.setAttributes(preparedAttrs.getValue());
 +                    tasks.add(task);
 +
 +                    LOG.debug("PropagationTask created: {}", task);
 +                }
 +            }
 +        }
 +
 +        return tasks;
 +    }
 +}


[25/54] [abbrv] syncope git commit: Upgrading swagger-jaxrs

Posted by fm...@apache.org.
Upgrading swagger-jaxrs


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

Branch: refs/heads/SYNCOPE-156
Commit: c5923de5a113dd7c8b0aa556fc98b2b3481aba87
Parents: f8d46d3
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Tue Oct 20 14:57:27 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Tue Oct 20 14:58:18 2015 +0200

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/c5923de5/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index b7ee843..059c4ac 100644
--- a/pom.xml
+++ b/pom.xml
@@ -505,7 +505,7 @@ under the License.
       <dependency>
         <groupId>io.swagger</groupId>
         <artifactId>swagger-jaxrs</artifactId>
-        <version>1.5.3</version>
+        <version>1.5.4</version>
         <exclusions>
           <exclusion>
             <groupId>javax.ws.rs</groupId>


[51/54] [abbrv] syncope git commit: refactoring of the policy stack , SYNCOPE-158

Posted by fm...@apache.org.
refactoring of the policy stack , SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 493133037c867b335f1e5f046bba8fa78ad40f55
Parents: 79d0316
Author: massi <ma...@tirasa.net>
Authored: Thu Oct 22 15:45:18 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Thu Oct 22 15:45:18 2015 +0200

----------------------------------------------------------------------
 .../commands/policy/AbstractPolicyCommand.java  |  30 +++++
 .../cli/commands/policy/PolicyDelete.java       |  59 +++++++++
 .../client/cli/commands/policy/PolicyList.java  |  59 +++++++++
 .../client/cli/commands/policy/PolicyRead.java  |  58 +++++++++
 .../commands/policy/PolicyResultManager.java    | 120 +++++++++++++++++++
 5 files changed, 326 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/49313303/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/AbstractPolicyCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/AbstractPolicyCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/AbstractPolicyCommand.java
new file mode 100644
index 0000000..0bab4e5
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/AbstractPolicyCommand.java
@@ -0,0 +1,30 @@
+/*
+ * 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.cli.commands.policy;
+
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.common.rest.api.service.PolicyService;
+
+public abstract class AbstractPolicyCommand {
+
+    protected final PolicyService policyService = SyncopeServices.get(PolicyService.class);
+    
+    protected final PolicyResultManager policyResultManager = new PolicyResultManager();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/49313303/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyDelete.java
new file mode 100644
index 0000000..15ffa8d
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyDelete.java
@@ -0,0 +1,59 @@
+/*
+ * 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.cli.commands.policy;
+
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+
+public class PolicyDelete extends AbstractPolicyCommand {
+
+    private static final String DELETE_HELP_MESSAGE = "policy --delete {POLICY-ID} {POLICY-ID} [...]";
+
+    private final Input input;
+
+    public PolicyDelete(final Input input) {
+        this.input = input;
+    }
+
+    public void delete() {
+        if (input.parameterNumber() >= 1) {
+            for (final String parameter : input.getParameters()) {
+                try {
+                    policyService.delete(Long.valueOf(parameter));
+                    policyResultManager.deletedMessage("Policy", parameter);
+                } catch (final WebServiceException | SyncopeClientException ex) {
+                    System.out.println("Error:");
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        policyResultManager.notFoundError("Policy", parameter);
+                    } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
+                        policyResultManager.generic("You cannot delete policy " + parameter);
+                    } else {
+                        policyResultManager.generic(ex.getMessage());
+                    }
+                } catch (final NumberFormatException ex) {
+                    policyResultManager.notBooleanDeletedError("policy", parameter);
+                }
+            }
+        } else {
+            policyResultManager.commandOptionError(DELETE_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/49313303/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyList.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyList.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyList.java
new file mode 100644
index 0000000..c05acf7
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyList.java
@@ -0,0 +1,59 @@
+/*
+ * 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.cli.commands.policy;
+
+import java.util.LinkedList;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.util.CommandUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
+import org.apache.syncope.common.lib.types.PolicyType;
+
+public class PolicyList extends AbstractPolicyCommand {
+
+    private static final String LIST_HELP_MESSAGE = "policy --list-policy {POLICY-TYPE}\n"
+            + "   Policy type: ACCOUNT / PASSWORD / SYNC / PUSH";
+
+    private final Input input;
+
+    public PolicyList(final Input input) {
+        this.input = input;
+    }
+
+    public void list() {
+
+        if (input.parameterNumber() == 1) {
+            try {
+                final PolicyType policyType = PolicyType.valueOf(input.firstParameter());
+                final LinkedList<AbstractPolicyTO> policyTOs = new LinkedList<>();
+                for (final AbstractPolicyTO policyTO : policyService.list(policyType)) {
+                    policyTOs.add(policyTO);
+                }
+                policyResultManager.fromList(policyType, policyTOs);
+            } catch (final SyncopeClientException ex) {
+                policyResultManager.generic(ex.getMessage());
+            } catch (final IllegalArgumentException ex) {
+                policyResultManager.typeNotValidError(
+                        "policy", input.firstParameter(), CommandUtils.fromEnumToArray(PolicyType.class));
+            }
+        } else {
+            policyResultManager.commandOptionError(LIST_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/49313303/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyRead.java
new file mode 100644
index 0000000..f20d41e
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyRead.java
@@ -0,0 +1,58 @@
+/*
+ * 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.cli.commands.policy;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
+
+public class PolicyRead extends AbstractPolicyCommand {
+
+    private static final String READ_HELP_MESSAGE = "policy --read {POLICY-ID} {POLICY-ID} [...]";
+
+    private final Input input;
+
+    public PolicyRead(final Input input) {
+        this.input = input;
+    }
+
+    public void read() {
+        if (input.parameterNumber() >= 1) {
+            final LinkedList<AbstractPolicyTO> policyTOs = new LinkedList<>();
+            for (final String parameter : input.getParameters()) {
+                try {
+                    policyTOs.add(policyService.read(Long.valueOf(parameter)));
+                    policyResultManager.fromRead(policyTOs);
+                } catch (final NumberFormatException ex) {
+                    policyResultManager.notBooleanDeletedError("policy", parameter);
+                } catch (final WebServiceException | SyncopeClientException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        policyResultManager.notFoundError("Policy", parameter);
+                    } else {
+                        policyResultManager.generic(ex.getMessage());
+                    }
+                }
+            }
+        } else {
+            policyResultManager.commandOptionError(READ_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/49313303/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyResultManager.java
new file mode 100644
index 0000000..88e40a0
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyResultManager.java
@@ -0,0 +1,120 @@
+/*
+ * 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.cli.commands.policy;
+
+import java.util.LinkedList;
+import org.apache.syncope.client.cli.commands.CommonsResultManager;
+import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
+import org.apache.syncope.common.lib.policy.AccountPolicyTO;
+import org.apache.syncope.common.lib.policy.PasswordPolicyTO;
+import org.apache.syncope.common.lib.policy.SyncPolicyTO;
+import org.apache.syncope.common.lib.types.PolicyType;
+
+public class PolicyResultManager extends CommonsResultManager {
+
+    public void fromRead(final LinkedList<AbstractPolicyTO> policyTOs) {
+        for (AbstractPolicyTO policyTO : policyTOs) {
+            if (!policyTOs.isEmpty()) {
+                final PolicyType policyType = policyTO.getType();
+                switch (policyType) {
+                    case ACCOUNT:
+                        printAccountPolicy((AccountPolicyTO) policyTO);
+                        break;
+                    case PASSWORD:
+                        printPasswordPolicy((PasswordPolicyTO) policyTO);
+                        break;
+                    case PUSH:
+                        System.out.println(policyTO);
+                        break;
+                    case SYNC:
+                        printSyncPolicy((SyncPolicyTO) policyTO);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+    }
+
+    public void fromList(final PolicyType policyType, final LinkedList<AbstractPolicyTO> policyTOs) {
+        switch (policyType) {
+            case ACCOUNT:
+                for (final AbstractPolicyTO policyTO : policyTOs) {
+                    printAccountPolicy((AccountPolicyTO) policyTO);
+                }
+                break;
+            case PASSWORD:
+                for (final AbstractPolicyTO policyTO : policyTOs) {
+                    printPasswordPolicy((PasswordPolicyTO) policyTO);
+                }
+                break;
+            case PUSH:
+                for (final AbstractPolicyTO policyTO : policyTOs) {
+                    System.out.println(policyTO);
+                }
+                break;
+            case SYNC:
+                for (final AbstractPolicyTO policyTO : policyTOs) {
+                    printSyncPolicy((SyncPolicyTO) policyTO);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    public void printAccountPolicy(final AccountPolicyTO policyTO) {
+        System.out.println(" > KEY: " + String.valueOf(policyTO.getKey()));
+        System.out.println("    type: " + policyTO.getType().name());
+        System.out.println("    description: " + policyTO.getDescription());
+        System.out.println("    resources : " + policyTO.getUsedByResources().toString());
+        System.out.println("    realms : " + policyTO.getUsedByRealms().toString());
+        System.out.println("    max authentication attempts : " + policyTO.getMaxAuthenticationAttempts());
+        System.out.println("    propagation suspension : " + policyTO.isPropagateSuspension());
+        System.out.println("    RULES : ");
+        System.out.println("       > class : " + policyTO.getRuleConfs());
+    }
+
+    public void printPasswordPolicy(final PasswordPolicyTO policyTO) {
+        System.out.println(" > KEY: " + String.valueOf(policyTO.getKey()));
+        System.out.println("    type: " + policyTO.getType().name());
+        System.out.println("    description: " + policyTO.getDescription());
+        System.out.println("    resources : " + policyTO.getUsedByResources().toString());
+        System.out.println("    realms : " + policyTO.getUsedByRealms().toString());
+        System.out.println("    history lenght : " + policyTO.getHistoryLength());
+        System.out.println("    allow null password : " + policyTO.isAllowNullPassword());
+        System.out.println("    RULES : ");
+        System.out.println("       > class : " + ((PasswordPolicyTO) policyTO).getRuleConfs());
+    }
+
+    public void printSyncPolicy(final SyncPolicyTO policyTO) {
+        System.out.println(" > KEY: " + String.valueOf(policyTO.getKey()));
+        System.out.println("    type: " + policyTO.getType().name());
+        System.out.println("    description: " + policyTO.getDescription());
+        System.out.println("    resources : " + policyTO.getUsedByResources().toString());
+        System.out.println("    realms : " + policyTO.getUsedByRealms().toString());
+        if (policyTO.getSpecification() != null) {
+            System.out.println("    conflict resolution action: "
+                    + policyTO.getSpecification().getConflictResolutionAction().name());
+            System.out.println("    correlation rule : "
+                    + policyTO.getSpecification().getCorrelationRules().toString());
+        }
+    }
+}


[48/54] [abbrv] syncope git commit: [SYNCOPE-709] Adding linking mapping items in ResourceTO, for info

Posted by fm...@apache.org.
[SYNCOPE-709] Adding linking mapping items in ResourceTO, for info


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

Branch: refs/heads/SYNCOPE-156
Commit: 55fdc58c959fae949cf660d008b9c670f97e37ae
Parents: fa5e65a
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 22 14:26:29 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 22 14:26:29 2015 +0200

----------------------------------------------------------------------
 .../org/apache/syncope/common/lib/to/MappingTO.java     |  9 +++++++++
 .../org/apache/syncope/common/lib/to/ProvisionTO.java   |  2 +-
 .../provisioning/java/data/ResourceDataBinderImpl.java  | 12 ++++++++----
 .../syncope/fit/core/reference/ResourceITCase.java      |  9 +++++++--
 4 files changed, 25 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/55fdc58c/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
index c573278..73c0523 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
@@ -40,6 +40,8 @@ public class MappingTO extends AbstractBaseBean {
 
     private final List<MappingItemTO> items = new ArrayList<>();
 
+    private final List<MappingItemTO> linkingItems = new ArrayList<>();
+
     public String getConnObjectLink() {
         return connObjectLink;
     }
@@ -96,4 +98,11 @@ public class MappingTO extends AbstractBaseBean {
     public boolean remove(final MappingItemTO item) {
         return this.items.remove(item);
     }
+
+    @XmlElementWrapper(name = "linkingItems")
+    @XmlElement(name = "item")
+    @JsonProperty("linkingItems")
+    public List<MappingItemTO> getLinkingItems() {
+        return linkingItems;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/55fdc58c/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisionTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisionTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisionTO.java
index b25053d..da23a59 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisionTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisionTO.java
@@ -43,7 +43,7 @@ public class ProvisionTO extends AbstractBaseBean {
 
     private MappingTO mapping;
 
-    private List<String> virSchemas = new ArrayList<>();
+    private final List<String> virSchemas = new ArrayList<>();
 
     public long getKey() {
         return key;

http://git-wip-us.apache.org/repos/asf/syncope/blob/55fdc58c/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index d04dfd3..388f099 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -299,10 +299,6 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
 
     @Override
     public ResourceTO getResourceTO(final ExternalResource resource) {
-        if (resource == null) {
-            return null;
-        }
-
         ResourceTO resourceTO = new ResourceTO();
 
         // set sys info
@@ -336,6 +332,14 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
 
             for (VirSchema virSchema : virSchemaDAO.findByProvision(provision)) {
                 provisionTO.getVirSchemas().add(virSchema.getKey());
+
+                MappingItem linkingMappingItem = virSchema.asLinkingMappingItem();
+
+                MappingItemTO itemTO = new MappingItemTO();
+                itemTO.setKey(linkingMappingItem.getKey());
+                BeanUtils.copyProperties(linkingMappingItem, itemTO, MAPPINGITEM_IGNORE_PROPERTIES);
+
+                provisionTO.getMapping().getLinkingItems().add(itemTO);
             }
 
             resourceTO.getProvisions().add(provisionTO);

http://git-wip-us.apache.org/repos/asf/syncope/blob/55fdc58c/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ResourceITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ResourceITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ResourceITCase.java
index 07433b7..e0539c8 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ResourceITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ResourceITCase.java
@@ -453,8 +453,13 @@ public class ResourceITCase extends AbstractITCase {
 
     @Test
     public void read() {
-        ResourceTO actual = resourceService.read(RESOURCE_NAME_TESTDB);
-        assertNotNull(actual);
+        ResourceTO resource = resourceService.read(RESOURCE_NAME_DBVIRATTR);
+        assertNotNull(resource);
+        
+        ProvisionTO provision = resource.getProvision(AnyTypeKind.USER.name());
+        assertNotNull(provision);
+        assertFalse(provision.getMapping().getItems().isEmpty());
+        assertFalse(provision.getMapping().getLinkingItems().isEmpty());
     }
 
     @Test


[34/54] [abbrv] syncope git commit: Massi remember that you have to add the licence header to the files, SYNCOPE-158

Posted by fm...@apache.org.
Massi remember that you have to add the licence header to the files, SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 469b7497c989ca9a892065ac81ac664a71790f01
Parents: 4f543e8
Author: massi <ma...@tirasa.net>
Authored: Wed Oct 21 12:34:57 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Wed Oct 21 12:34:57 2015 +0200

----------------------------------------------------------------------
 .../commands/install/InstallResultManager.java    | 18 ++++++++++++++++++
 .../client/cli/commands/install/InstallSetup.java | 18 ++++++++++++++++++
 2 files changed, 36 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/469b7497/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallResultManager.java
index 994aca6..8b96ae0 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallResultManager.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallResultManager.java
@@ -1,3 +1,21 @@
+/*
+ * 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.cli.commands.install;
 
 import java.net.ConnectException;

http://git-wip-us.apache.org/repos/asf/syncope/blob/469b7497/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
index 2a4079e..1486b48 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallSetup.java
@@ -1,3 +1,21 @@
+/*
+ * 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.cli.commands.install;
 
 import java.io.FileNotFoundException;


[52/54] [abbrv] syncope git commit: Upgrading ConnId

Posted by fm...@apache.org.
Upgrading ConnId


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

Branch: refs/heads/SYNCOPE-156
Commit: 23d8047389206d870450ab73e0f7bf24c3d65e2e
Parents: 4931330
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 22 16:36:12 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 22 16:36:12 2015 +0200

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/23d80473/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 059c4ac..e2cee9b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -319,7 +319,7 @@ under the License.
   <properties>
     <syncope.version>${project.version}</syncope.version>
 
-    <connid.version>1.4.2.0-SNAPSHOT</connid.version>
+    <connid.version>1.4.2.0</connid.version>
     <connid.soap.version>1.4.0-SNAPSHOT</connid.soap.version>
     <connid.database.version>2.2.3-SNAPSHOT</connid.database.version>
     <connid.csvdir.version>0.8.2</connid.csvdir.version>


[04/54] [abbrv] syncope git commit: [SYNCOPE-710] Merge from 1_2_X

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --cc core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
index 6b4f838,0000000..48092ee
mode 100644,000000..100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
@@@ -1,853 -1,0 +1,866 @@@
 +/*
 + * 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.workflow.activiti;
 +
 +import com.fasterxml.jackson.databind.JsonNode;
 +import com.fasterxml.jackson.databind.ObjectMapper;
 +import com.fasterxml.jackson.databind.node.ObjectNode;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.OutputStream;
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +import javax.annotation.Resource;
 +import javax.ws.rs.NotFoundException;
 +import org.activiti.bpmn.converter.BpmnXMLConverter;
 +import org.activiti.bpmn.model.BpmnModel;
 +import org.activiti.editor.constants.ModelDataJsonConstants;
 +import org.activiti.editor.language.json.converter.BpmnJsonConverter;
 +import org.activiti.engine.ActivitiException;
 +import org.activiti.engine.ProcessEngine;
 +import org.activiti.engine.form.FormProperty;
 +import org.activiti.engine.form.FormType;
 +import org.activiti.engine.form.TaskFormData;
 +import org.activiti.engine.history.HistoricActivityInstance;
 +import org.activiti.engine.history.HistoricDetail;
 +import org.activiti.engine.history.HistoricTaskInstance;
 +import org.activiti.engine.impl.persistence.entity.HistoricFormPropertyEntity;
 +import org.activiti.engine.query.Query;
 +import org.activiti.engine.repository.Model;
 +import org.activiti.engine.repository.ProcessDefinition;
 +import org.activiti.engine.runtime.ProcessInstance;
 +import org.activiti.engine.task.Task;
 +import org.apache.commons.io.IOUtils;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.patch.PasswordPatch;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.to.WorkflowFormPropertyTO;
 +import org.apache.syncope.common.lib.to.WorkflowFormTO;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.common.lib.types.ResourceOperation;
 +import org.apache.syncope.common.lib.types.WorkflowFormPropertyType;
 +import org.apache.syncope.core.misc.security.AuthContextUtils;
 +import org.apache.syncope.core.misc.spring.BeanUtils;
 +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.entity.user.User;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 +import org.apache.syncope.core.workflow.api.WorkflowDefinitionFormat;
 +import org.apache.syncope.core.workflow.api.WorkflowException;
 +import org.apache.syncope.core.workflow.java.AbstractUserWorkflowAdapter;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.transaction.annotation.Transactional;
 +
 +/**
 + * Activiti {@link http://www.activiti.org/} based implementation.
 + */
 +public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 +
 +    protected static final String[] PROPERTY_IGNORE_PROPS = { "type" };
 +
 +    public static final String WF_PROCESS_ID = "userWorkflow";
 +
 +    public static final String WF_PROCESS_RESOURCE = "userWorkflow.bpmn20.xml";
 +
 +    public static final String WF_DGRM_RESOURCE = "userWorkflow.userWorkflow.png";
 +
 +    public static final String USER = "user";
 +
 +    public static final String WF_EXECUTOR = "wfExecutor";
 +
 +    public static final String FORM_SUBMITTER = "formSubmitter";
 +
 +    public static final String USER_TO = "userTO";
 +
 +    public static final String ENABLED = "enabled";
 +
 +    public static final String USER_PATCH = "userPatch";
 +
 +    public static final String EMAIL_KIND = "emailKind";
 +
 +    public static final String TASK = "task";
 +
 +    public static final String TOKEN = "token";
 +
 +    public static final String PASSWORD = "password";
 +
 +    public static final String PROP_BY_RESOURCE = "propByResource";
 +
 +    public static final String PROPAGATE_ENABLE = "propagateEnable";
 +
 +    public static final String ENCRYPTED_PWD = "encryptedPwd";
 +
 +    public static final String TASK_IS_FORM = "taskIsForm";
 +
 +    public static final String MODEL_DATA_JSON_MODEL = "model";
 +
 +    public static final String STORE_PASSWORD = "storePassword";
 +
 +    public static final String EVENT = "event";
 +
 +    @Resource(name = "adminUser")
 +    protected String adminUser;
 +
 +    @Autowired
 +    protected ProcessEngine engine;
 +
 +    @Autowired
 +    protected UserDataBinder userDataBinder;
 +
 +    @Override
 +    public String getPrefix() {
 +        return "ACT_";
 +    }
 +
 +    protected void throwException(final ActivitiException e, final String defaultMessage) {
 +        if (e.getCause() != null) {
 +            if (e.getCause().getCause() instanceof SyncopeClientException) {
 +                throw (SyncopeClientException) e.getCause().getCause();
 +            } else if (e.getCause().getCause() instanceof ParsingValidationException) {
 +                throw (ParsingValidationException) e.getCause().getCause();
 +            } else if (e.getCause().getCause() instanceof InvalidEntityException) {
 +                throw (InvalidEntityException) e.getCause().getCause();
 +            }
 +        }
 +
 +        throw new WorkflowException(defaultMessage, e);
 +    }
 +
 +    protected void updateStatus(final User user) {
 +        List<Task> tasks = engine.getTaskService().createTaskQuery().processInstanceId(user.getWorkflowId()).list();
 +        if (tasks.isEmpty() || tasks.size() > 1) {
 +            LOG.warn("While setting user status: unexpected task number ({})", tasks.size());
 +        } else {
 +            user.setStatus(tasks.get(0).getTaskDefinitionKey());
 +        }
 +    }
 +
 +    protected String getFormTask(final User user) {
 +        String result = null;
 +
 +        List<Task> tasks = engine.getTaskService().createTaskQuery().processInstanceId(user.getWorkflowId()).list();
 +        if (tasks.isEmpty() || tasks.size() > 1) {
 +            LOG.warn("While checking if form task: unexpected task number ({})", tasks.size());
 +        } else {
 +            try {
 +                TaskFormData formData = engine.getFormService().getTaskFormData(tasks.get(0).getId());
 +                if (formData != null && !formData.getFormProperties().isEmpty()) {
 +                    result = tasks.get(0).getId();
 +                }
 +            } catch (ActivitiException e) {
 +                LOG.warn("Could not get task form data", e);
 +            }
 +        }
 +
 +        return result;
 +    }
 +
 +    protected Set<String> getPerformedTasks(final User user) {
 +        final Set<String> result = new HashSet<>();
 +
 +        for (HistoricActivityInstance task : engine.getHistoryService().createHistoricActivityInstanceQuery().
 +                executionId(user.getWorkflowId()).list()) {
 +
 +            result.add(task.getActivityId());
 +        }
 +
 +        return result;
 +    }
 +
 +    /**
 +     * Saves resources to be propagated and password for later - after form submission - propagation.
 +     */
 +    protected void saveForFormSubmit(final User user, final String password, final PropagationByResource propByRes) {
 +        String formTaskId = getFormTask(user);
 +        if (formTaskId != null) {
 +            // SYNCOPE-238: This is needed to simplify the task query in this.getForms()
 +            engine.getTaskService().setVariableLocal(formTaskId, TASK_IS_FORM, Boolean.TRUE);
 +            engine.getRuntimeService().setVariable(user.getWorkflowId(), PROP_BY_RESOURCE, propByRes);
 +            if (propByRes != null) {
 +                propByRes.clear();
 +            }
 +
 +            if (StringUtils.isNotBlank(password)) {
 +                engine.getRuntimeService().setVariable(user.getWorkflowId(), ENCRYPTED_PWD, encrypt(password));
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public WorkflowResult<Pair<Long, Boolean>> create(final UserTO userTO, final boolean disablePwdPolicyCheck,
 +            final boolean storePassword) {
 +
 +        return create(userTO, disablePwdPolicyCheck, null, storePassword);
 +    }
 +
 +    @Override
 +    public WorkflowResult<Pair<Long, Boolean>> create(final UserTO userTO, final boolean storePassword) {
 +        return create(userTO, false, storePassword);
 +    }
 +
 +    @Override
 +    public WorkflowResult<Pair<Long, Boolean>> create(final UserTO userTO, final boolean disablePwdPolicyCheck,
 +            final Boolean enabled, final boolean storePassword) {
 +
 +        Map<String, Object> variables = new HashMap<>();
 +        variables.put(WF_EXECUTOR, AuthContextUtils.getUsername());
 +        variables.put(USER_TO, userTO);
 +        variables.put(ENABLED, enabled);
 +        variables.put(STORE_PASSWORD, storePassword);
 +
 +        ProcessInstance processInstance = null;
 +        try {
 +            processInstance = engine.getRuntimeService().startProcessInstanceByKey(WF_PROCESS_ID, variables);
 +        } catch (ActivitiException e) {
 +            throwException(e, "While starting " + WF_PROCESS_ID + " instance");
 +        }
 +
 +        User user = engine.getRuntimeService().getVariable(processInstance.getProcessInstanceId(), USER, User.class);
 +
 +        Boolean updatedEnabled =
 +                engine.getRuntimeService().getVariable(processInstance.getProcessInstanceId(), ENABLED, Boolean.class);
 +        if (updatedEnabled != null) {
 +            user.setSuspended(!updatedEnabled);
 +        }
 +
 +        // this will make UserValidator not to consider password policies at all
 +        if (disablePwdPolicyCheck) {
 +            user.removeClearPassword();
 +        }
 +
 +        updateStatus(user);
 +        user = userDAO.save(user);
 +
 +        Boolean propagateEnable = engine.getRuntimeService().getVariable(
 +                processInstance.getProcessInstanceId(), PROPAGATE_ENABLE, Boolean.class);
 +        if (propagateEnable == null) {
 +            propagateEnable = enabled;
 +        }
 +
 +        PropagationByResource propByRes = new PropagationByResource();
 +        propByRes.set(ResourceOperation.CREATE, userDAO.findAllResourceNames(user));
 +
 +        saveForFormSubmit(user, userTO.getPassword(), propByRes);
 +
 +        return new WorkflowResult<Pair<Long, Boolean>>(
 +                new ImmutablePair<>(user.getKey(), propagateEnable), propByRes, getPerformedTasks(user));
 +    }
 +
 +    protected Set<String> doExecuteTask(final User user, final String task, final Map<String, Object> moreVariables) {
 +        Set<String> preTasks = getPerformedTasks(user);
 +
 +        Map<String, Object> variables = new HashMap<>();
 +        variables.put(WF_EXECUTOR, AuthContextUtils.getUsername());
 +        variables.put(TASK, task);
 +
 +        // using BeanUtils to access all user's properties and trigger lazy loading - we are about to
 +        // serialize a User instance for availability within workflow tasks, and this breaks transactions
 +        BeanUtils.copyProperties(user, entityFactory.newEntity(User.class));
 +        variables.put(USER, user);
 +
 +        if (moreVariables != null && !moreVariables.isEmpty()) {
 +            variables.putAll(moreVariables);
 +        }
 +
 +        if (StringUtils.isBlank(user.getWorkflowId())) {
 +            throw new WorkflowException(new NotFoundException("Empty workflow id for " + user));
 +        }
 +
 +        List<Task> tasks = engine.getTaskService().createTaskQuery().processInstanceId(user.getWorkflowId()).list();
 +        if (tasks.size() == 1) {
 +            try {
 +                engine.getTaskService().complete(tasks.get(0).getId(), variables);
 +            } catch (ActivitiException e) {
 +                throwException(e, "While completing task '" + tasks.get(0).getName() + "' for " + user);
 +            }
 +        } else {
 +            LOG.warn("Expected a single task, found {}", tasks.size());
 +        }
 +
 +        Set<String> postTasks = getPerformedTasks(user);
 +        postTasks.removeAll(preTasks);
 +        postTasks.add(task);
 +        return postTasks;
 +    }
 +
 +    @Override
 +    protected WorkflowResult<Long> doActivate(final User user, final String token) {
 +        Set<String> tasks = doExecuteTask(user, "activate", Collections.singletonMap(TOKEN, (Object) token));
 +
 +        updateStatus(user);
 +        User updated = userDAO.save(user);
 +
 +        return new WorkflowResult<>(updated.getKey(), null, tasks);
 +    }
 +
 +    @Override
 +    protected WorkflowResult<Pair<UserPatch, Boolean>> doUpdate(final User user, final UserPatch userPatch) {
 +        Set<String> tasks = doExecuteTask(user, "update", Collections.singletonMap(USER_PATCH, (Object) userPatch));
 +
 +        updateStatus(user);
 +        User updated = userDAO.save(user);
 +
 +        PropagationByResource propByRes = engine.getRuntimeService().getVariable(
 +                user.getWorkflowId(), PROP_BY_RESOURCE, PropagationByResource.class);
 +        UserPatch updatedPatch = engine.getRuntimeService().getVariable(
 +                user.getWorkflowId(), USER_PATCH, UserPatch.class);
 +
 +        saveForFormSubmit(
 +                updated, updatedPatch.getPassword() == null ? null : updatedPatch.getPassword().getValue(), propByRes);
 +
 +        Boolean propagateEnable = engine.getRuntimeService().getVariable(
 +                user.getWorkflowId(), PROPAGATE_ENABLE, Boolean.class);
 +
 +        return new WorkflowResult<Pair<UserPatch, Boolean>>(
 +                new ImmutablePair<>(updatedPatch, propagateEnable), propByRes, tasks);
 +    }
 +
 +    @Override
 +    protected WorkflowResult<Long> doSuspend(final User user) {
 +        Set<String> performedTasks = doExecuteTask(user, "suspend", null);
 +        updateStatus(user);
 +        User updated = userDAO.save(user);
 +
 +        return new WorkflowResult<>(updated.getKey(), null, performedTasks);
 +    }
 +
 +    @Override
 +    protected WorkflowResult<Long> doReactivate(final User user) {
 +        Set<String> performedTasks = doExecuteTask(user, "reactivate", null);
 +        updateStatus(user);
 +
 +        User updated = userDAO.save(user);
 +
 +        return new WorkflowResult<>(updated.getKey(), null, performedTasks);
 +    }
 +
 +    @Override
 +    protected void doRequestPasswordReset(final User user) {
 +        Map<String, Object> variables = new HashMap<>(2);
 +        variables.put(USER_TO, userDataBinder.getUserTO(user, true));
 +        variables.put(EVENT, "requestPasswordReset");
 +
 +        doExecuteTask(user, "requestPasswordReset", variables);
 +        userDAO.save(user);
 +    }
 +
 +    @Override
-     protected void doConfirmPasswordReset(final User user, final String token, final String password) {
++    protected WorkflowResult<Pair<UserPatch, Boolean>> doConfirmPasswordReset(
++            final User user, final String token, final String password) {
++
 +        Map<String, Object> variables = new HashMap<>(4);
 +        variables.put(TOKEN, token);
 +        variables.put(PASSWORD, password);
 +        variables.put(USER_TO, userDataBinder.getUserTO(user, true));
 +        variables.put(EVENT, "confirmPasswordReset");
 +
-         doExecuteTask(user, "confirmPasswordReset", variables);
++        Set<String> tasks = doExecuteTask(user, "confirmPasswordReset", variables);
++
 +        userDAO.save(user);
++
++        PropagationByResource propByRes = engine.getRuntimeService().getVariable(
++                user.getWorkflowId(), PROP_BY_RESOURCE, PropagationByResource.class);
++        UserPatch updatedPatch = engine.getRuntimeService().getVariable(
++                user.getWorkflowId(), USER_PATCH, UserPatch.class);
++        Boolean propagateEnable = engine.getRuntimeService().getVariable(
++                user.getWorkflowId(), PROPAGATE_ENABLE, Boolean.class);
++
++        return new WorkflowResult<Pair<UserPatch, Boolean>>(
++                new ImmutablePair<>(updatedPatch, propagateEnable), propByRes, tasks);
 +    }
 +
 +    @Override
 +    protected void doDelete(final User user) {
 +        doExecuteTask(user, "delete", null);
 +
 +        PropagationByResource propByRes = new PropagationByResource();
 +        propByRes.set(ResourceOperation.DELETE, userDAO.findAllResourceNames(user));
 +
 +        saveForFormSubmit(user, null, propByRes);
 +
 +        if (engine.getRuntimeService().createProcessInstanceQuery().
 +                processInstanceId(user.getWorkflowId()).active().list().isEmpty()) {
 +
 +            userDAO.delete(user.getKey());
 +
 +            if (!engine.getHistoryService().createHistoricProcessInstanceQuery().
 +                    processInstanceId(user.getWorkflowId()).list().isEmpty()) {
 +
 +                engine.getHistoryService().deleteHistoricProcessInstance(user.getWorkflowId());
 +            }
 +        } else {
 +            updateStatus(user);
 +            userDAO.save(user);
 +        }
 +    }
 +
 +    @Override
 +    public WorkflowResult<Long> execute(final UserTO userTO, final String taskId) {
 +        User user = userDAO.authFind(userTO.getKey());
 +
 +        final Map<String, Object> variables = new HashMap<>();
 +        variables.put(USER_TO, userTO);
 +
 +        Set<String> performedTasks = doExecuteTask(user, taskId, variables);
 +        updateStatus(user);
 +        User updated = userDAO.save(user);
 +
 +        return new WorkflowResult<>(updated.getKey(), null, performedTasks);
 +    }
 +
 +    protected ProcessDefinition getProcessDefinition() {
 +        try {
 +            return engine.getRepositoryService().createProcessDefinitionQuery().processDefinitionKey(
 +                    ActivitiUserWorkflowAdapter.WF_PROCESS_ID).latestVersion().singleResult();
 +        } catch (ActivitiException e) {
 +            throw new WorkflowException("While accessing process " + ActivitiUserWorkflowAdapter.WF_PROCESS_ID, e);
 +        }
 +
 +    }
 +
 +    protected Model getModel(final ProcessDefinition procDef) {
 +        try {
 +            Model model = engine.getRepositoryService().createModelQuery().
 +                    deploymentId(procDef.getDeploymentId()).singleResult();
 +            if (model == null) {
 +                throw new NotFoundException("Could not find Model for deployment " + procDef.getDeploymentId());
 +            }
 +            return model;
 +        } catch (Exception e) {
 +            throw new WorkflowException("While accessing process " + ActivitiUserWorkflowAdapter.WF_PROCESS_ID, e);
 +        }
 +    }
 +
 +    protected void exportProcessResource(final String resourceName, final OutputStream os) {
 +        ProcessDefinition procDef = getProcessDefinition();
 +
 +        InputStream procDefIS = engine.getRepositoryService().getResourceAsStream(procDef.getDeploymentId(),
 +                resourceName);
 +        try {
 +            IOUtils.copy(procDefIS, os);
 +        } catch (IOException e) {
 +            LOG.error("While exporting workflow definition {}", procDef.getKey(), e);
 +        } finally {
 +            IOUtils.closeQuietly(procDefIS);
 +        }
 +    }
 +
 +    protected void exportProcessModel(final OutputStream os) {
 +        Model model = getModel(getProcessDefinition());
 +
 +        ObjectMapper objectMapper = new ObjectMapper();
 +        try {
 +            ObjectNode modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
 +            modelNode.put(ModelDataJsonConstants.MODEL_ID, model.getId());
 +            modelNode.replace(MODEL_DATA_JSON_MODEL,
 +                    objectMapper.readTree(engine.getRepositoryService().getModelEditorSource(model.getId())));
 +
 +            os.write(modelNode.toString().getBytes());
 +        } catch (IOException e) {
 +            LOG.error("While exporting workflow definition {}", model.getId(), e);
 +        }
 +    }
 +
 +    @Override
 +    public void exportDefinition(final WorkflowDefinitionFormat format, final OutputStream os) {
 +        switch (format) {
 +            case JSON:
 +                exportProcessModel(os);
 +                break;
 +
 +            case XML:
 +            default:
 +                exportProcessResource(WF_PROCESS_RESOURCE, os);
 +        }
 +    }
 +
 +    @Override
 +    public void exportDiagram(final OutputStream os) {
 +        exportProcessResource(WF_DGRM_RESOURCE, os);
 +    }
 +
 +    @Override
 +    public void importDefinition(final WorkflowDefinitionFormat format, final String definition) {
 +        Model model = getModel(getProcessDefinition());
 +        switch (format) {
 +            case JSON:
 +                JsonNode definitionNode;
 +                try {
 +                    definitionNode = new ObjectMapper().readTree(definition);
 +                    if (definitionNode.has(MODEL_DATA_JSON_MODEL)) {
 +                        definitionNode = definitionNode.get(MODEL_DATA_JSON_MODEL);
 +                    }
 +                    if (!definitionNode.has(BpmnJsonConverter.EDITOR_CHILD_SHAPES)) {
 +                        throw new IllegalArgumentException(
 +                                "Could not find JSON node " + BpmnJsonConverter.EDITOR_CHILD_SHAPES);
 +                    }
 +
 +                    BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(definitionNode);
 +                    ActivitiImportUtils.fromXML(engine, new BpmnXMLConverter().convertToXML(bpmnModel));
 +                } catch (Exception e) {
 +                    throw new WorkflowException("While updating process "
 +                            + ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE, e);
 +                }
 +
 +                ActivitiImportUtils.fromJSON(
 +                        engine, definitionNode.toString().getBytes(), getProcessDefinition(), model);
 +                break;
 +
 +            case XML:
 +            default:
 +                ActivitiImportUtils.fromXML(engine, definition.getBytes());
 +
 +                ActivitiImportUtils.fromJSON(engine, getProcessDefinition(), model);
 +        }
 +    }
 +
 +    protected WorkflowFormPropertyType fromActivitiFormType(final FormType activitiFormType) {
 +        WorkflowFormPropertyType result = WorkflowFormPropertyType.String;
 +
 +        if ("string".equals(activitiFormType.getName())) {
 +            result = WorkflowFormPropertyType.String;
 +        }
 +        if ("long".equals(activitiFormType.getName())) {
 +            result = WorkflowFormPropertyType.Long;
 +        }
 +        if ("enum".equals(activitiFormType.getName())) {
 +            result = WorkflowFormPropertyType.Enum;
 +        }
 +        if ("date".equals(activitiFormType.getName())) {
 +            result = WorkflowFormPropertyType.Date;
 +        }
 +        if ("boolean".equals(activitiFormType.getName())) {
 +            result = WorkflowFormPropertyType.Boolean;
 +        }
 +
 +        return result;
 +    }
 +
 +    protected WorkflowFormTO getFormTO(final Task task) {
 +        return getFormTO(task, engine.getFormService().getTaskFormData(task.getId()));
 +    }
 +
 +    protected WorkflowFormTO getFormTO(final Task task, final TaskFormData fd) {
 +        final WorkflowFormTO formTO =
 +                getFormTO(task.getProcessInstanceId(), task.getId(), fd.getFormKey(), fd.getFormProperties());
 +
 +        BeanUtils.copyProperties(task, formTO);
 +        return formTO;
 +    }
 +
 +    protected WorkflowFormTO getFormTO(final HistoricTaskInstance task) {
 +        final List<HistoricFormPropertyEntity> props = new ArrayList<>();
 +
 +        for (HistoricDetail historicDetail
 +                : engine.getHistoryService().createHistoricDetailQuery().taskId(task.getId()).list()) {
 +
 +            if (historicDetail instanceof HistoricFormPropertyEntity) {
 +                props.add((HistoricFormPropertyEntity) historicDetail);
 +            }
 +        }
 +
 +        final WorkflowFormTO formTO = getHistoricFormTO(
 +                task.getProcessInstanceId(), task.getId(), task.getFormKey(), props);
 +        BeanUtils.copyProperties(task, formTO);
 +
 +        final HistoricActivityInstance historicActivityInstance = engine.getHistoryService().
 +                createHistoricActivityInstanceQuery().
 +                executionId(task.getExecutionId()).activityType("userTask").activityName(task.getName()).singleResult();
 +
 +        if (historicActivityInstance != null) {
 +            formTO.setCreateTime(historicActivityInstance.getStartTime());
 +            formTO.setDueDate(historicActivityInstance.getEndTime());
 +        }
 +
 +        return formTO;
 +    }
 +
 +    protected WorkflowFormTO getHistoricFormTO(
 +            final String processInstanceId,
 +            final String taskId,
 +            final String formKey,
 +            final List<HistoricFormPropertyEntity> props) {
 +
 +        WorkflowFormTO formTO = new WorkflowFormTO();
 +
 +        User user = userDAO.findByWorkflowId(processInstanceId);
 +        if (user == null) {
 +            throw new NotFoundException("User with workflow id " + processInstanceId);
 +        }
 +        formTO.setUserKey(user.getKey());
 +
 +        formTO.setTaskId(taskId);
 +        formTO.setKey(formKey);
 +
 +        for (HistoricFormPropertyEntity prop : props) {
 +            WorkflowFormPropertyTO propertyTO = new WorkflowFormPropertyTO();
 +            propertyTO.setId(prop.getPropertyId());
 +            propertyTO.setName(prop.getPropertyId());
 +            propertyTO.setValue(prop.getPropertyValue());
 +            formTO.addProperty(propertyTO);
 +        }
 +
 +        return formTO;
 +    }
 +
 +    @SuppressWarnings("unchecked")
 +    protected WorkflowFormTO getFormTO(
 +            final String processInstanceId,
 +            final String taskId,
 +            final String formKey,
 +            final List<FormProperty> properties) {
 +
 +        WorkflowFormTO formTO = new WorkflowFormTO();
 +
 +        User user = userDAO.findByWorkflowId(processInstanceId);
 +        if (user == null) {
 +            throw new NotFoundException("User with workflow id " + processInstanceId);
 +        }
 +        formTO.setUserKey(user.getKey());
 +
 +        formTO.setTaskId(taskId);
 +        formTO.setKey(formKey);
 +
 +        for (FormProperty fProp : properties) {
 +            WorkflowFormPropertyTO propertyTO = new WorkflowFormPropertyTO();
 +            BeanUtils.copyProperties(fProp, propertyTO, PROPERTY_IGNORE_PROPS);
 +            propertyTO.setType(fromActivitiFormType(fProp.getType()));
 +
 +            if (propertyTO.getType() == WorkflowFormPropertyType.Date) {
 +                propertyTO.setDatePattern((String) fProp.getType().getInformation("datePattern"));
 +            }
 +            if (propertyTO.getType() == WorkflowFormPropertyType.Enum) {
 +                propertyTO.getEnumValues().putAll((Map<String, String>) fProp.getType().getInformation("values"));
 +            }
 +
 +            formTO.addProperty(propertyTO);
 +        }
 +
 +        return formTO;
 +    }
 +
 +    @Transactional(readOnly = true)
 +    @Override
 +    public List<WorkflowFormTO> getForms() {
 +        List<WorkflowFormTO> forms = new ArrayList<>();
 +
 +        String authUser = AuthContextUtils.getUsername();
 +        if (adminUser.equals(authUser)) {
 +            forms.addAll(getForms(engine.getTaskService().createTaskQuery().
 +                    taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE)));
 +        } else {
 +            User user = userDAO.find(authUser);
 +            if (user == null) {
 +                throw new NotFoundException("Syncope User " + authUser);
 +            }
 +
 +            forms.addAll(getForms(engine.getTaskService().createTaskQuery().
 +                    taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE).
 +                    taskCandidateOrAssigned(user.getKey().toString())));
 +
 +            List<String> candidateGroups = new ArrayList<>();
 +            for (Long groupId : userDAO.findAllGroupKeys(user)) {
 +                candidateGroups.add(groupId.toString());
 +            }
 +            if (!candidateGroups.isEmpty()) {
 +                forms.addAll(getForms(engine.getTaskService().createTaskQuery().
 +                        taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE).
 +                        taskCandidateGroupIn(candidateGroups)));
 +            }
 +        }
 +
 +        return forms;
 +    }
 +
 +    @Override
 +    public List<WorkflowFormTO> getForms(final String workflowId, final String name) {
 +        List<WorkflowFormTO> forms = getForms(
 +                engine.getTaskService().createTaskQuery().processInstanceId(workflowId).taskName(name).
 +                taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE));
 +
 +        forms.addAll(getForms(engine.getHistoryService().createHistoricTaskInstanceQuery().taskName(name).
 +                taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE)));
 +
 +        return forms;
 +    }
 +
 +    protected <T extends Query<?, ?>, U extends Object> List<WorkflowFormTO> getForms(final Query<T, U> query) {
 +        List<WorkflowFormTO> forms = new ArrayList<>();
 +
 +        for (U obj : query.list()) {
 +            try {
 +                if (obj instanceof HistoricTaskInstance) {
 +                    forms.add(getFormTO((HistoricTaskInstance) obj));
 +                } else if (obj instanceof Task) {
 +                    forms.add(getFormTO((Task) obj));
 +                } else {
 +                    throw new ActivitiException(
 +                            "Failure retrieving form", new IllegalArgumentException("Invalid task type"));
 +                }
 +            } catch (ActivitiException e) {
 +                LOG.debug("No form found for task {}", obj, e);
 +            }
 +        }
 +
 +        return forms;
 +    }
 +
 +    @Override
 +    public WorkflowFormTO getForm(final String workflowId) {
 +        Task task;
 +        try {
 +            task = engine.getTaskService().createTaskQuery().processInstanceId(workflowId).singleResult();
 +        } catch (ActivitiException e) {
 +            throw new WorkflowException("While reading form for workflow instance " + workflowId, e);
 +        }
 +
 +        TaskFormData formData;
 +        try {
 +            formData = engine.getFormService().getTaskFormData(task.getId());
 +        } catch (ActivitiException e) {
 +            LOG.debug("No form found for task {}", task.getId(), e);
 +            formData = null;
 +        }
 +
 +        WorkflowFormTO result = null;
 +        if (formData != null && !formData.getFormProperties().isEmpty()) {
 +            result = getFormTO(task);
 +        }
 +
 +        return result;
 +    }
 +
 +    protected Pair<Task, TaskFormData> checkTask(final String taskId, final String authUser) {
 +        Task task;
 +        try {
 +            task = engine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
 +        } catch (ActivitiException e) {
 +            throw new NotFoundException("Activiti Task " + taskId, e);
 +        }
 +
 +        TaskFormData formData;
 +        try {
 +            formData = engine.getFormService().getTaskFormData(task.getId());
 +        } catch (ActivitiException e) {
 +            throw new NotFoundException("Form for Activiti Task " + taskId, e);
 +        }
 +
 +        if (!adminUser.equals(authUser)) {
 +            User user = userDAO.find(authUser);
 +            if (user == null) {
 +                throw new NotFoundException("Syncope User " + authUser);
 +            }
 +        }
 +
 +        return new ImmutablePair<>(task, formData);
 +    }
 +
 +    @Override
 +    public WorkflowFormTO claimForm(final String taskId) {
 +        String authUser = AuthContextUtils.getUsername();
 +        Pair<Task, TaskFormData> checked = checkTask(taskId, authUser);
 +
 +        if (!adminUser.equals(authUser)) {
 +            List<Task> tasksForUser = engine.getTaskService().createTaskQuery().taskId(taskId).taskCandidateUser(
 +                    authUser).list();
 +            if (tasksForUser.isEmpty()) {
 +                throw new WorkflowException(
 +                        new IllegalArgumentException(authUser + " is not candidate for task " + taskId));
 +            }
 +        }
 +
 +        Task task;
 +        try {
 +            engine.getTaskService().setOwner(taskId, authUser);
 +            task = engine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
 +        } catch (ActivitiException e) {
 +            throw new WorkflowException("While reading task " + taskId, e);
 +        }
 +
 +        return getFormTO(task, checked.getValue());
 +    }
 +
 +    @Override
 +    public WorkflowResult<UserPatch> submitForm(final WorkflowFormTO form) {
 +        String authUser = AuthContextUtils.getUsername();
 +        Pair<Task, TaskFormData> checked = checkTask(form.getTaskId(), authUser);
 +
 +        if (!checked.getKey().getOwner().equals(authUser)) {
 +            throw new WorkflowException(new IllegalArgumentException("Task " + form.getTaskId() + " assigned to "
 +                    + checked.getKey().getOwner() + " but submitted by " + authUser));
 +        }
 +
 +        User user = userDAO.findByWorkflowId(checked.getKey().getProcessInstanceId());
 +        if (user == null) {
 +            throw new NotFoundException("User with workflow id " + checked.getKey().getProcessInstanceId());
 +        }
 +
 +        Set<String> preTasks = getPerformedTasks(user);
 +        try {
 +            engine.getFormService().submitTaskFormData(form.getTaskId(), form.getPropertiesForSubmit());
 +            engine.getRuntimeService().setVariable(user.getWorkflowId(), FORM_SUBMITTER, authUser);
 +        } catch (ActivitiException e) {
 +            throwException(e, "While submitting form for task " + form.getTaskId());
 +        }
 +
 +        Set<String> postTasks = getPerformedTasks(user);
 +        postTasks.removeAll(preTasks);
 +        postTasks.add(form.getTaskId());
 +
 +        updateStatus(user);
 +        User updated = userDAO.save(user);
 +
 +        // see if there is any propagation to be done
 +        PropagationByResource propByRes = engine.getRuntimeService().getVariable(
 +                user.getWorkflowId(), PROP_BY_RESOURCE, PropagationByResource.class);
 +
 +        // fetch - if available - the encrypted password
 +        String clearPassword = null;
 +        String encryptedPwd = engine.getRuntimeService().getVariable(user.getWorkflowId(), ENCRYPTED_PWD, String.class);
 +        if (StringUtils.isNotBlank(encryptedPwd)) {
 +            clearPassword = decrypt(encryptedPwd);
 +        }
 +
 +        // supports approval chains
 +        saveForFormSubmit(user, clearPassword, propByRes);
 +
 +        UserPatch userPatch = engine.getRuntimeService().getVariable(user.getWorkflowId(), USER_PATCH, UserPatch.class);
 +        if (userPatch == null) {
 +            userPatch = new UserPatch();
 +            userPatch.setKey(updated.getKey());
 +            userPatch.setPassword(new PasswordPatch.Builder().onSyncope(true).value(clearPassword).build());
 +
 +            if (propByRes != null) {
 +                userPatch.getPassword().getResources().addAll(propByRes.get(ResourceOperation.CREATE));
 +            }
 +        }
 +
 +        return new WorkflowResult<>(userPatch, propByRes, postTasks);
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/PasswordReset.java
----------------------------------------------------------------------
diff --cc core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/PasswordReset.java
index 10e9afe,0000000..91b4bf4
mode 100644,000000..100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/PasswordReset.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/PasswordReset.java
@@@ -1,47 -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.core.workflow.activiti.task;
 +
++import org.apache.syncope.common.lib.patch.PasswordPatch;
++import org.apache.syncope.common.lib.patch.UserPatch;
++import org.apache.syncope.common.lib.types.PropagationByResource;
++import org.apache.syncope.core.persistence.api.dao.UserDAO;
 +import org.apache.syncope.core.persistence.api.entity.user.User;
++import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 +import org.apache.syncope.core.workflow.api.WorkflowException;
 +import org.apache.syncope.core.workflow.activiti.ActivitiUserWorkflowAdapter;
++import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.stereotype.Component;
 +
 +@Component
 +public class PasswordReset extends AbstractActivitiServiceTask {
 +
++    @Autowired
++    private UserDAO userDAO;
++
++    @Autowired
++    private UserDataBinder dataBinder;
++
 +    @Override
 +    protected void doExecute(final String executionId) {
 +        User user = engine.getRuntimeService().
 +                getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
 +        String token = engine.getRuntimeService().
 +                getVariable(executionId, ActivitiUserWorkflowAdapter.TOKEN, String.class);
 +        String password = engine.getRuntimeService().
 +                getVariable(executionId, ActivitiUserWorkflowAdapter.PASSWORD, String.class);
 +
 +        if (!user.checkToken(token)) {
 +            throw new WorkflowException(new IllegalArgumentException("Wrong token: " + token + " for " + user));
 +        }
 +
 +        user.removeToken();
-         user.setPassword(password, user.getCipherAlgorithm());
++
++        UserPatch userPatch = new UserPatch();
++        userPatch.setKey(user.getKey());
++        userPatch.setPassword(new PasswordPatch.Builder().
++                onSyncope(true).resources(userDAO.findAllResourceNames(user)).value(password).build());
++
++        PropagationByResource propByRes = dataBinder.update(user, userPatch);
++
++        // report updated user and propagation by resource as result
 +        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.USER, user);
++        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.USER_PATCH, userPatch);
++        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.PROP_BY_RESOURCE, propByRes);
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Update.java
----------------------------------------------------------------------
diff --cc core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Update.java
index 21498ac,0000000..4448938
mode 100644,000000..100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Update.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Update.java
@@@ -1,66 -1,0 +1,49 @@@
 +/*
 + * 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.workflow.activiti.task;
 +
- import org.apache.commons.lang3.SerializationUtils;
- import org.apache.syncope.common.lib.patch.PasswordPatch;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.core.persistence.api.entity.user.User;
 +import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 +import org.apache.syncope.core.workflow.activiti.ActivitiUserWorkflowAdapter;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.stereotype.Component;
 +
 +@Component
 +public class Update extends AbstractActivitiServiceTask {
 +
 +    @Autowired
 +    private UserDataBinder dataBinder;
 +
 +    @Override
 +    protected void doExecute(final String executionId) {
 +        User user = engine.getRuntimeService().
 +                getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
 +        UserPatch userPatch = engine.getRuntimeService().
 +                getVariable(executionId, ActivitiUserWorkflowAdapter.USER_PATCH, UserPatch.class);
 +
-         // update password internally only if required
-         UserPatch updatedPatch = SerializationUtils.clone(userPatch);
-         PasswordPatch updatedPwd = updatedPatch.getPassword();
-         if (updatedPatch.getPassword() != null && !updatedPatch.getPassword().isOnSyncope()) {
-             updatedPatch.setPassword(null);
-         }
-         // update user
-         PropagationByResource propByRes = dataBinder.update(user, updatedPatch);
-         if (updatedPatch.getPassword() != null && !updatedPatch.getPassword().getResources().isEmpty()) {
-             if (updatedPwd == null) {
-                 updatedPwd = updatedPatch.getPassword();
-             } else {
-                 updatedPwd.getResources().addAll(updatedPatch.getPassword().getResources());
-             }
-         }
-         updatedPatch.setPassword(updatedPwd);
++        PropagationByResource propByRes = dataBinder.update(user, userPatch);
 +
 +        // report updated user and propagation by resource as result
 +        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.USER, user);
-         engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.USER_PATCH, updatedPatch);
++        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.USER_PATCH, userPatch);
 +        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.PROP_BY_RESOURCE, propByRes);
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java
----------------------------------------------------------------------
diff --cc core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java
index 51c3e77,0000000..91a83aa
mode 100644,000000..100644
--- a/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java
+++ b/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java
@@@ -1,135 -1,0 +1,136 @@@
 +/*
 + * 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.workflow.api;
 +
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.common.lib.to.UserTO;
 +
 +/**
 + * Interface for calling underlying workflow implementations.
 + */
 +public interface UserWorkflowAdapter extends WorkflowAdapter {
 +
 +    /**
 +     * Create an user.
 +     *
 +     * @param userTO user to be created and whether to propagate it as active
 +     * @param storePassword whether password shall be stored into the internal storage
 +     * @return user just created
 +     */
 +    WorkflowResult<Pair<Long, Boolean>> create(UserTO userTO, boolean storePassword);
 +
 +    /**
 +     * Create an user, optionally disabling password policy check.
 +     *
 +     * @param userTO user to be created and whether to propagate it as active
 +     * @param disablePwdPolicyCheck disable password policy check?
 +     * @param storePassword whether password shall be stored into the internal storage
 +     * @return user just created
 +     */
 +    WorkflowResult<Pair<Long, Boolean>> create(
 +            UserTO userTO, boolean disablePwdPolicyCheck, boolean storePassword);
 +
 +    /**
 +     * Create an user, optionally disabling password policy check.
 +     *
 +     * @param userTO user to be created and whether to propagate it as active
 +     * @param disablePwdPolicyCheck disable password policy check?
 +     * @param enabled specify true/false to force active/supended status
 +     * @param storePassword whether password shall be stored into the internal storage
 +     * @return user just created
 +     */
 +    WorkflowResult<Pair<Long, Boolean>> create(
 +            UserTO userTO, boolean disablePwdPolicyCheck, final Boolean enabled, boolean storePassword);
 +
 +    /**
 +     * Execute a task on an user.
 +     *
 +     * @param userTO user to be subject to task
 +     * @param taskId to be executed
 +     * @return user just updated
 +     */
 +    WorkflowResult<Long> execute(UserTO userTO, String taskId);
 +
 +    /**
 +     * Activate an user.
 +     *
 +     * @param userKey user to be activated
 +     * @param token to be verified for activation
 +     * @return user just updated
 +     */
 +    WorkflowResult<Long> activate(Long userKey, String token);
 +
 +    /**
 +     * Update an user.
 +     *
 +     * @param userPatch modification set to be performed
 +     * @return user just updated and propagations to be performed
 +     */
 +    WorkflowResult<Pair<UserPatch, Boolean>> update(UserPatch userPatch);
 +
 +    /**
 +     * Suspend an user.
 +     *
 +     * @param key to be suspended
 +     * @return user just suspended
 +     */
 +    WorkflowResult<Long> suspend(Long key);
 +
 +    /**
 +     * Suspend an user (used by internal authentication process)
 +     *
 +     * @param key to be suspended
 +     * @return user just suspended and information whether to propagate suspension
 +     */
 +    Pair<WorkflowResult<Long>, Boolean> internalSuspend(Long key);
 +
 +    /**
 +     * Reactivate an user.
 +     *
 +     * @param userKey user to be reactivated
 +     * @return user just reactivated
 +     */
 +    WorkflowResult<Long> reactivate(Long userKey);
 +
 +    /**
 +     * Request password reset for an user.
 +     *
 +     * @param userKey user requesting password reset
 +     */
 +    void requestPasswordReset(Long userKey);
 +
 +    /**
 +     * Confirm password reset for an user.
 +     *
 +     * @param userKey user confirming password reset
 +     * @param token security token
 +     * @param password new password value
++     * @return user just updated and propagations to be performed
 +     */
-     void confirmPasswordReset(Long userKey, String token, String password);
++    WorkflowResult<Pair<UserPatch, Boolean>> confirmPasswordReset(Long userKey, String token, String password);
 +
 +    /**
 +     * Delete an user.
 +     *
 +     * @param userKey user to be deleted
 +     */
 +    void delete(Long userKey);
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --cc core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
index 4236cff,0000000..716090f
mode 100644,000000..100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
@@@ -1,150 -1,0 +1,153 @@@
 +/*
 + * 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.workflow.java;
 +
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.core.persistence.api.dao.UserDAO;
 +import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 +import org.apache.syncope.core.persistence.api.entity.user.User;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 +import org.apache.syncope.core.workflow.api.UserWorkflowAdapter;
 +import org.identityconnectors.common.Base64;
 +import org.identityconnectors.common.security.EncryptorFactory;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.transaction.annotation.Propagation;
 +import org.springframework.transaction.annotation.Transactional;
 +
 +@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = { Throwable.class })
 +public abstract class AbstractUserWorkflowAdapter implements UserWorkflowAdapter {
 +
 +    protected static final Logger LOG = LoggerFactory.getLogger(UserWorkflowAdapter.class);
 +
 +    @Autowired
 +    protected UserDataBinder dataBinder;
 +
 +    @Autowired
 +    protected UserDAO userDAO;
 +
 +    @Autowired
 +    protected EntityFactory entityFactory;
 +
 +    public static String encrypt(final String clear) {
 +        byte[] encryptedBytes = EncryptorFactory.getInstance().getDefaultEncryptor().encrypt(clear.getBytes());
 +        return Base64.encode(encryptedBytes);
 +    }
 +
 +    public static String decrypt(final String crypted) {
 +        byte[] decryptedBytes = EncryptorFactory.getInstance().getDefaultEncryptor().decrypt(Base64.decode(crypted));
 +        return new String(decryptedBytes);
 +    }
 +
 +    @Override
 +    public String getPrefix() {
 +        return null;
 +    }
 +
 +    protected abstract WorkflowResult<Long> doActivate(User user, String token);
 +
 +    @Override
 +    public WorkflowResult<Long> activate(final Long key, final String token) {
 +        return doActivate(userDAO.authFind(key), token);
 +    }
 +
 +    protected abstract WorkflowResult<Pair<UserPatch, Boolean>> doUpdate(User user, UserPatch userPatch);
 +
 +    @Override
 +    public WorkflowResult<Pair<UserPatch, Boolean>> update(final UserPatch userPatch) {
 +        return doUpdate(userDAO.authFind(userPatch.getKey()), userPatch);
 +    }
 +
 +    protected abstract WorkflowResult<Long> doSuspend(User user);
 +
 +    @Override
 +    public WorkflowResult<Long> suspend(final Long key) {
 +        User user = userDAO.authFind(key);
 +
 +        // set suspended flag
 +        user.setSuspended(Boolean.TRUE);
 +
 +        return doSuspend(user);
 +    }
 +
 +    @Override
 +    public Pair<WorkflowResult<Long>, Boolean> internalSuspend(final Long key) {
 +        User user = userDAO.authFind(key);
 +
 +        Pair<WorkflowResult<Long>, Boolean> result = null;
 +
 +        Pair<Boolean, Boolean> enforce = userDAO.enforcePolicies(user);
 +        if (enforce.getKey()) {
 +            LOG.debug("User {} {} is over the max failed logins", user.getKey(), user.getUsername());
 +
 +            // reduce failed logins number to avoid multiple request       
 +            user.setFailedLogins(user.getFailedLogins() - 1);
 +
 +            // set suspended flag
 +            user.setSuspended(Boolean.TRUE);
 +
 +            result = ImmutablePair.of(doSuspend(user), enforce.getValue());
 +        }
 +
 +        return result;
 +    }
 +
 +    protected abstract WorkflowResult<Long> doReactivate(User user);
 +
 +    @Override
 +    public WorkflowResult<Long> reactivate(final Long key) {
 +        User user = userDAO.authFind(key);
 +
 +        // reset failed logins
 +        user.setFailedLogins(0);
 +
 +        // reset suspended flag
 +        user.setSuspended(Boolean.FALSE);
 +
 +        return doReactivate(user);
 +    }
 +
 +    protected abstract void doRequestPasswordReset(User user);
 +
 +    @Override
 +    public void requestPasswordReset(final Long key) {
 +        doRequestPasswordReset(userDAO.authFind(key));
 +    }
 +
-     protected abstract void doConfirmPasswordReset(User user, String token, String password);
++    protected abstract WorkflowResult<Pair<UserPatch, Boolean>> doConfirmPasswordReset(
++            User user, String token, String password);
 +
 +    @Override
-     public void confirmPasswordReset(final Long key, final String token, final String password) {
-         doConfirmPasswordReset(userDAO.authFind(key), token, password);
++    public WorkflowResult<Pair<UserPatch, Boolean>> confirmPasswordReset(
++            final Long key, final String token, final String password) {
++
++        return doConfirmPasswordReset(userDAO.authFind(key), token, password);
 +    }
 +
 +    protected abstract void doDelete(User user);
 +
 +    @Override
 +    public void delete(final Long key) {
 +        doDelete(userDAO.authFind(key));
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --cc core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
index 1d70394,0000000..5592eef
mode 100644,000000..100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
@@@ -1,218 -1,0 +1,209 @@@
 +/*
 + * 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.workflow.java;
 +
 +import java.io.OutputStream;
 +import java.util.Collections;
 +import java.util.List;
- import org.apache.commons.lang3.SerializationUtils;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.patch.PasswordPatch;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.to.WorkflowFormTO;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.common.lib.types.ResourceOperation;
 +import org.apache.syncope.core.persistence.api.dao.ConfDAO;
 +import org.apache.syncope.core.persistence.api.entity.user.User;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.workflow.api.WorkflowDefinitionFormat;
 +import org.apache.syncope.core.workflow.api.WorkflowException;
 +import org.springframework.beans.factory.annotation.Autowired;
 +
 +/**
 + * Simple implementation basically not involving any workflow engine.
 + */
 +public class DefaultUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 +
 +    @Autowired
 +    private ConfDAO confDAO;
 +
 +    @Override
 +    public WorkflowResult<Pair<Long, Boolean>> create(final UserTO userTO, final boolean storePassword) {
 +        return create(userTO, false, true);
 +    }
 +
 +    @Override
 +    public WorkflowResult<Pair<Long, Boolean>> create(final UserTO userTO, final boolean disablePwdPolicyCheck,
 +            final boolean storePassword) {
 +
 +        return create(userTO, disablePwdPolicyCheck, null, storePassword);
 +    }
 +
 +    @Override
 +    public WorkflowResult<Pair<Long, Boolean>> create(final UserTO userTO, final boolean disablePwdPolicyCheck,
 +            final Boolean enabled, final boolean storePassword) {
 +
 +        User user = entityFactory.newEntity(User.class);
 +        dataBinder.create(user, userTO, storePassword);
 +
 +        // this will make UserValidator not to consider password policies at all
 +        if (disablePwdPolicyCheck) {
 +            user.removeClearPassword();
 +        }
 +
 +        String status;
 +        boolean propagateEnable;
 +        if (enabled == null) {
 +            status = "created";
 +            propagateEnable = true;
 +        } else {
 +            status = enabled
 +                    ? "active"
 +                    : "suspended";
 +            propagateEnable = enabled;
 +            user.setSuspended(!enabled);
 +        }
 +
 +        user.setStatus(status);
 +        user = userDAO.save(user);
 +
 +        final PropagationByResource propByRes = new PropagationByResource();
 +        propByRes.set(ResourceOperation.CREATE, userDAO.findAllResourceNames(user));
 +
 +        return new WorkflowResult<Pair<Long, Boolean>>(
 +                new ImmutablePair<>(user.getKey(), propagateEnable), propByRes, "create");
 +    }
 +
 +    @Override
 +    protected WorkflowResult<Long> doActivate(final User user, final String token) {
 +        if (!user.checkToken(token)) {
 +            throw new WorkflowException(new IllegalArgumentException("Wrong token: " + token + " for " + user));
 +        }
 +
 +        user.removeToken();
 +        user.setStatus("active");
 +        User updated = userDAO.save(user);
 +
 +        return new WorkflowResult<>(updated.getKey(), null, "activate");
 +    }
 +
 +    @Override
 +    protected WorkflowResult<Pair<UserPatch, Boolean>> doUpdate(final User user, final UserPatch userPatch) {
-         // update password internally only if required
-         UserPatch updatedPatch = SerializationUtils.clone(userPatch);
-         PasswordPatch updatedPwd = updatedPatch.getPassword();
-         if (updatedPatch.getPassword() != null && !updatedPatch.getPassword().isOnSyncope()) {
-             updatedPatch.setPassword(null);
-         }
-         // update User
-         PropagationByResource propByRes = dataBinder.update(user, updatedPatch);
-         if (updatedPatch.getPassword() != null && !updatedPatch.getPassword().getResources().isEmpty()) {
-             if (updatedPwd == null) {
-                 updatedPwd = updatedPatch.getPassword();
-             } else {
-                 updatedPwd.getResources().addAll(updatedPatch.getPassword().getResources());
-             }
-         }
-         updatedPatch.setPassword(updatedPwd);
++        PropagationByResource propByRes = dataBinder.update(user, userPatch);
 +
 +        userDAO.save(user);
 +
 +        return new WorkflowResult<Pair<UserPatch, Boolean>>(
-                 new ImmutablePair<>(updatedPatch, !user.isSuspended()), propByRes, "update");
++                new ImmutablePair<>(userPatch, !user.isSuspended()), propByRes, "update");
 +    }
 +
 +    @Override
 +    protected WorkflowResult<Long> doSuspend(final User user) {
 +        user.setStatus("suspended");
 +        User updated = userDAO.save(user);
 +
 +        return new WorkflowResult<>(updated.getKey(), null, "suspend");
 +    }
 +
 +    @Override
 +    protected WorkflowResult<Long> doReactivate(final User user) {
 +        user.setStatus("active");
 +        User updated = userDAO.save(user);
 +
 +        return new WorkflowResult<>(updated.getKey(), null, "reactivate");
 +    }
 +
 +    @Override
 +    protected void doRequestPasswordReset(final User user) {
 +        user.generateToken(
 +                confDAO.find("token.length", "256").getValues().get(0).getLongValue().intValue(),
 +                confDAO.find("token.expireTime", "60").getValues().get(0).getLongValue().intValue());
 +        userDAO.save(user);
 +    }
 +
 +    @Override
-     protected void doConfirmPasswordReset(final User user, final String token, final String password) {
++    protected WorkflowResult<Pair<UserPatch, Boolean>> doConfirmPasswordReset(
++            final User user, final String token, final String password) {
++
 +        if (!user.checkToken(token)) {
 +            throw new WorkflowException(new IllegalArgumentException("Wrong token: " + token + " for " + user));
 +        }
 +
 +        user.removeToken();
-         user.setPassword(password, user.getCipherAlgorithm());
-         userDAO.save(user);
++
++        UserPatch userPatch = new UserPatch();
++        userPatch.setKey(user.getKey());
++        userPatch.setPassword(new PasswordPatch.Builder().
++                onSyncope(true).resources(userDAO.findAllResourceNames(user)).value(password).build());
++
++        return doUpdate(user, userPatch);
 +    }
 +
 +    @Override
 +    protected void doDelete(final User user) {
 +        userDAO.delete(user);
 +    }
 +
 +    @Override
 +    public WorkflowResult<Long> execute(final UserTO userTO, final String taskId) {
 +        throw new WorkflowException(new UnsupportedOperationException("Not supported."));
 +    }
 +
 +    @Override
 +    public void exportDefinition(final WorkflowDefinitionFormat format, final OutputStream os) {
 +        throw new WorkflowException(new UnsupportedOperationException("Not supported."));
 +    }
 +
 +    @Override
 +    public void exportDiagram(final OutputStream os) {
 +        throw new WorkflowException(new UnsupportedOperationException("Not supported."));
 +    }
 +
 +    @Override
 +    public void importDefinition(final WorkflowDefinitionFormat format, final String definition) {
 +        throw new WorkflowException(new UnsupportedOperationException("Not supported."));
 +    }
 +
 +    @Override
 +    public List<WorkflowFormTO> getForms() {
 +        return Collections.emptyList();
 +    }
 +
 +    @Override
 +    public List<WorkflowFormTO> getForms(final String workflowId, final String name) {
 +        return Collections.emptyList();
 +    }
 +
 +    @Override
 +    public WorkflowFormTO getForm(final String workflowId) {
 +        return null;
 +    }
 +
 +    @Override
 +    public WorkflowFormTO claimForm(final String taskId) {
 +        throw new WorkflowException(new UnsupportedOperationException("Not supported."));
 +    }
 +
 +    @Override
 +    public WorkflowResult<UserPatch> submitForm(final WorkflowFormTO form) {
 +        throw new WorkflowException(new UnsupportedOperationException("Not supported."));
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
----------------------------------------------------------------------
diff --cc ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
index 978388d,0000000..158cc09
mode 100644,000000..100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
@@@ -1,102 -1,0 +1,95 @@@
 +/*
 + * 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.provisioning.camel.processor;
 +
- import java.util.Collections;
 +import java.util.List;
 +import java.util.Set;
 +import org.apache.camel.Exchange;
 +import org.apache.camel.Processor;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.syncope.common.lib.patch.AnyObjectPatch;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 +import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.stereotype.Component;
 +
 +@Component
 +public class AnyObjectUpdateProcessor implements Processor {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(UserUpdateProcessor.class);
 +
 +    @Autowired
 +    protected PropagationManager propagationManager;
 +
 +    @Autowired
 +    protected PropagationTaskExecutor taskExecutor;
 +
 +    @Autowired
 +    protected VirAttrHandler virtAttrHandler;
 +
 +    @SuppressWarnings("unchecked")
 +    @Override
 +    public void process(final Exchange exchange) {
 +        WorkflowResult<Long> updated = (WorkflowResult) exchange.getIn().getBody();
 +        AnyObjectPatch anyObjectPatch = exchange.getProperty("anyPatch", AnyObjectPatch.class);
 +        Set<String> excludedResources = exchange.getProperty("excludedResources", Set.class);
 +
++        // SYNCOPE-459: take care of user virtual attributes ...
++        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
++                updated.getResult(),
++                AnyTypeKind.ANY_OBJECT,
++                anyObjectPatch.getVirAttrs());
++        if (updated.getPropByRes() == null) {
++            updated.setPropByRes(propByResVirAttr);
++        } else {
++            updated.getPropByRes().merge(propByResVirAttr);
++        }
++
 +        List<PropagationTask> tasks = propagationManager.getUpdateTasks(
 +                AnyTypeKind.ANY_OBJECT,
 +                updated.getResult(),
 +                false,
 +                null,
 +                updated.getPropByRes(),
 +                anyObjectPatch.getVirAttrs(),
 +                excludedResources);
-         if (tasks.isEmpty()) {
-             // SYNCOPE-459: take care of user virtual attributes ...
-             PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                     updated.getResult(),
-                     AnyTypeKind.ANY_OBJECT,
-                     anyObjectPatch.getVirAttrs());
-             tasks.addAll(!propByResVirAttr.isEmpty()
-                     ? propagationManager.getUpdateTasks(
-                             AnyTypeKind.ANY_OBJECT,
-                             updated.getResult(),
-                             false,
-                             null,
-                             updated.getPropByRes(),
-                             anyObjectPatch.getVirAttrs(),
-                             null)
-                     : Collections.<PropagationTask>emptyList());
-         }
 +
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        exchange.getOut().setBody(new ImmutablePair<>(updated.getResult(), propagationReporter.getStatuses()));
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/GroupUpdateProcessor.java
----------------------------------------------------------------------
diff --cc ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/GroupUpdateProcessor.java
index ad9ed63,0000000..22868bf
mode 100644,000000..100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/GroupUpdateProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/GroupUpdateProcessor.java
@@@ -1,102 -1,0 +1,95 @@@
 +/*
 + * 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.provisioning.camel.processor;
 +
- import java.util.Collections;
 +import java.util.List;
 +import java.util.Set;
 +import org.apache.camel.Exchange;
 +import org.apache.camel.Processor;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.syncope.common.lib.patch.GroupPatch;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
 +import org.apache.syncope.common.lib.types.PropagationByResource;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 +import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.stereotype.Component;
 +
 +@Component
 +public class GroupUpdateProcessor implements Processor {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(UserUpdateProcessor.class);
 +
 +    @Autowired
 +    protected PropagationManager propagationManager;
 +
 +    @Autowired
 +    protected PropagationTaskExecutor taskExecutor;
 +
 +    @Autowired
 +    protected VirAttrHandler virtAttrHandler;
 +
 +    @SuppressWarnings("unchecked")
 +    @Override
 +    public void process(final Exchange exchange) {
 +        WorkflowResult<Long> updated = (WorkflowResult) exchange.getIn().getBody();
 +        GroupPatch groupPatch = exchange.getProperty("anyPatch", GroupPatch.class);
 +        Set<String> excludedResources = exchange.getProperty("excludedResources", Set.class);
 +
++        // SYNCOPE-459: take care of user virtual attributes ...
++        PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
++                updated.getResult(),
++                AnyTypeKind.GROUP,
++                groupPatch.getVirAttrs());
++        if (updated.getPropByRes() == null) {
++            updated.setPropByRes(propByResVirAttr);
++        } else {
++            updated.getPropByRes().merge(propByResVirAttr);
++        }
++
 +        List<PropagationTask> tasks = propagationManager.getUpdateTasks(
 +                AnyTypeKind.GROUP,
 +                updated.getResult(),
 +                false,
 +                null,
 +                updated.getPropByRes(),
 +                groupPatch.getVirAttrs(),
 +                excludedResources);
-         if (tasks.isEmpty()) {
-             // SYNCOPE-459: take care of user virtual attributes ...
-             PropagationByResource propByResVirAttr = virtAttrHandler.updateVirtual(
-                     updated.getResult(),
-                     AnyTypeKind.GROUP,
-                     groupPatch.getVirAttrs());
-             tasks.addAll(!propByResVirAttr.isEmpty()
-                     ? propagationManager.getUpdateTasks(
-                             AnyTypeKind.GROUP,
-                             updated.getResult(),
-                             false,
-                             null,
-                             updated.getPropByRes(),
-                             groupPatch.getVirAttrs(),
-                             excludedResources)
-                     : Collections.<PropagationTask>emptyList());
-         }
 +
 +        PropagationReporter propagationReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        exchange.getOut().setBody(new ImmutablePair<>(updated.getResult(), propagationReporter.getStatuses()));
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
----------------------------------------------------------------------
diff --cc ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
index 1e02187,0000000..8a19609
mode 100644,000000..100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
@@@ -1,73 -1,0 +1,65 @@@
 +/*
 + * 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.provisioning.camel.processor;
 +
 +import java.util.List;
 +import org.apache.camel.Exchange;
 +import org.apache.camel.Processor;
- import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.commons.lang3.tuple.Pair;
- import org.apache.syncope.common.lib.patch.PasswordPatch;
 +import org.apache.syncope.common.lib.patch.UserPatch;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.stereotype.Component;
 +
 +@Component
 +public class UserConfirmPwdResetProcessor implements Processor {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(UserConfirmPwdResetProcessor.class);
 +
 +    @Autowired
 +    protected PropagationManager propagationManager;
 +
 +    @Autowired
 +    protected PropagationTaskExecutor taskExecutor;
 +
 +    @Override
 +    public void process(final Exchange exchange) {
-         Long key = exchange.getProperty("userKey", Long.class);
++        @SuppressWarnings("unchecked")
++        WorkflowResult<Pair<UserPatch, Boolean>> updated = (WorkflowResult) exchange.getIn().getBody();
 +
-         UserPatch userPatch = new UserPatch();
-         userPatch.setKey(key);
-         userPatch.setPassword(new PasswordPatch.Builder().
-                 value(exchange.getProperty("password", String.class)).build());
++        List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(updated);
 +
-         List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
-                 new WorkflowResult<Pair<UserPatch, Boolean>>(
-                         new ImmutablePair<UserPatch, Boolean>(userPatch, null), null, "confirmPasswordReset"),
-                 true, null);
 +        PropagationReporter propReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propReporter.onPrimaryResourceFailure(tasks);
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2011671c/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserStatusPropagationProcessor.java
----------------------------------------------------------------------
diff --cc ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserStatusPropagationProcessor.java
index da6e745,0000000..068f003
mode 100644,000000..100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserStatusPropagationProcessor.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserStatusPropagationProcessor.java
@@@ -1,87 -1,0 +1,86 @@@
 +/*
 + * 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.provisioning.camel.processor;
 +
- import java.util.Collection;
 +import java.util.List;
 +import org.apache.camel.Exchange;
 +import org.apache.camel.Processor;
- import org.apache.commons.collections4.CollectionUtils;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.syncope.common.lib.patch.StatusPatch;
 +import org.apache.syncope.common.lib.types.AnyTypeKind;
++import org.apache.syncope.common.lib.types.PropagationByResource;
++import org.apache.syncope.common.lib.types.ResourceOperation;
 +import org.apache.syncope.common.lib.types.StatusPatchType;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.persistence.api.dao.UserDAO;
 +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 +import org.apache.syncope.core.provisioning.api.WorkflowResult;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.stereotype.Component;
 +
 +@Component
 +public class UserStatusPropagationProcessor implements Processor {
 +
 +    private static final Logger LOG = LoggerFactory.getLogger(UserStatusPropagationProcessor.class);
 +
 +    @Autowired
 +    protected PropagationManager propagationManager;
 +
 +    @Autowired
 +    protected PropagationTaskExecutor taskExecutor;
 +
 +    @Autowired
 +    protected UserDAO userDAO;
 +
 +    @SuppressWarnings("unchecked")
 +    @Override
 +    public void process(final Exchange exchange) {
 +        WorkflowResult<Long> updated = (WorkflowResult) exchange.getIn().getBody();
 +
-         Long key = exchange.getProperty("userKey", Long.class);
 +        StatusPatch statusPatch = exchange.getProperty("statusPatch", StatusPatch.class);
 +
-         Collection<String> noPropResourceNames = CollectionUtils.removeAll(
-                 userDAO.findAllResourceNames(userDAO.find(key)), statusPatch.getResources());
- 
++        PropagationByResource propByRes = new PropagationByResource();
++        propByRes.addAll(ResourceOperation.UPDATE, statusPatch.getResources());
 +        List<PropagationTask> tasks = propagationManager.getUpdateTasks(
 +                AnyTypeKind.USER,
 +                statusPatch.getKey(),
 +                false,
 +                statusPatch.getType() != StatusPatchType.SUSPEND,
++                propByRes,
 +                null,
-                 null,
-                 noPropResourceNames);
++                null);
++
 +        PropagationReporter propReporter =
 +                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        exchange.getOut().setBody(new ImmutablePair<>(updated.getResult(), propReporter.getStatuses()));
 +    }
 +}


[49/54] [abbrv] syncope git commit: [SYNCOPE-709] Fixing build with Java 1.7

Posted by fm...@apache.org.
[SYNCOPE-709] Fixing build with Java 1.7


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

Branch: refs/heads/SYNCOPE-156
Commit: 15f6d19dc49006be90bdce1b3859510a4a471066
Parents: 55fdc58
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 22 15:19:00 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 22 15:19:00 2015 +0200

----------------------------------------------------------------------
 .../api/entity/LinkingMappingItem.java          | 140 +++++++++++++++++++
 .../persistence/jpa/entity/JPAVirSchema.java    | 111 +--------------
 2 files changed, 142 insertions(+), 109 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/15f6d19d/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/LinkingMappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/LinkingMappingItem.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/LinkingMappingItem.java
new file mode 100644
index 0000000..46fcedc
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/LinkingMappingItem.java
@@ -0,0 +1,140 @@
+/*
+ * 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.persistence.api.entity;
+
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+
+/**
+ * {@link MappingItem} implementation for usage within {@link VirSchema#asLinkingMappingItem()} implementations.
+ */
+public class LinkingMappingItem implements MappingItem {
+
+    private static final long serialVersionUID = 327455459536715529L;
+
+    private final VirSchema virSchema;
+
+    public LinkingMappingItem(final VirSchema virSchema) {
+        this.virSchema = virSchema;
+    }
+
+    @Override
+    public Long getKey() {
+        return -1L;
+    }
+
+    @Override
+    public Mapping getMapping() {
+        return virSchema.getProvision().getMapping();
+    }
+
+    @Override
+    public void setMapping(final Mapping mapping) {
+        // RO instance, nothing to do
+    }
+
+    @Override
+    public String getExtAttrName() {
+        return virSchema.getExtAttrName();
+    }
+
+    @Override
+    public void setExtAttrName(final String extAttrName) {
+        // RO instance, nothing to do
+    }
+
+    @Override
+    public String getIntAttrName() {
+        return virSchema.getKey();
+    }
+
+    @Override
+    public void setIntAttrName(final String intAttrName) {
+        // RO instance, nothing to do
+    }
+
+    @Override
+    public IntMappingType getIntMappingType() {
+        switch (virSchema.getProvision().getAnyType().getKind()) {
+            case ANY_OBJECT:
+                return IntMappingType.AnyObjectVirtualSchema;
+
+            case GROUP:
+                return IntMappingType.GroupVirtualSchema;
+
+            case USER:
+            default:
+                return IntMappingType.UserVirtualSchema;
+        }
+    }
+
+    @Override
+    public void setIntMappingType(final IntMappingType intMappingType) {
+        // RO instance, nothing to do
+    }
+
+    @Override
+    public String getMandatoryCondition() {
+        return virSchema.getMandatoryCondition();
+    }
+
+    @Override
+    public void setMandatoryCondition(final String condition) {
+        // RO instance, nothing to do
+    }
+
+    @Override
+    public MappingPurpose getPurpose() {
+        return virSchema.isReadonly() ? MappingPurpose.SYNCHRONIZATION : MappingPurpose.BOTH;
+    }
+
+    @Override
+    public void setPurpose(final MappingPurpose purpose) {
+        // RO instance, nothing to do
+    }
+
+    @Override
+    public boolean isConnObjectKey() {
+        return false;
+    }
+
+    @Override
+    public void setConnObjectKey(final boolean connObjectKey) {
+        // RO instance, nothing to do
+    }
+
+    @Override
+    public boolean isPassword() {
+        return false;
+    }
+
+    @Override
+    public void setPassword(final boolean password) {
+        // RO instance, nothing to do
+    }
+
+    @Override
+    public List<String> getMappingItemTransformerClassNames() {
+        return Collections.emptyList();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/15f6d19d/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
index 419e93a..0ee1606 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.core.persistence.jpa.entity;
 
-import java.util.Collections;
-import java.util.List;
 import javax.persistence.Basic;
 import javax.persistence.Cacheable;
 import javax.persistence.Entity;
@@ -32,11 +30,9 @@ import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
 import javax.validation.constraints.NotNull;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
-import org.apache.syncope.common.lib.types.IntMappingType;
-import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
+import org.apache.syncope.core.persistence.api.entity.LinkingMappingItem;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
-import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAProvision;
@@ -150,110 +146,7 @@ public class JPAVirSchema extends AbstractEntity<String> implements VirSchema {
 
     @Override
     public MappingItem asLinkingMappingItem() {
-        return new MappingItem() {
-
-            private static final long serialVersionUID = 327455459536715529L;
-
-            @Override
-            public Long getKey() {
-                return -1L;
-            }
-
-            @Override
-            public Mapping getMapping() {
-                return getProvision().getMapping();
-            }
-
-            @Override
-            public void setMapping(final Mapping mapping) {
-                // RO instance, nothing to do
-            }
-
-            @Override
-            public String getExtAttrName() {
-                return JPAVirSchema.this.getExtAttrName();
-            }
-
-            @Override
-            public void setExtAttrName(final String extAttrName) {
-                // RO instance, nothing to do
-            }
-
-            @Override
-            public String getIntAttrName() {
-                return JPAVirSchema.this.getKey();
-            }
-
-            @Override
-            public void setIntAttrName(final String intAttrName) {
-                // RO instance, nothing to do
-            }
-
-            @Override
-            public IntMappingType getIntMappingType() {
-                switch (getProvision().getAnyType().getKind()) {
-                    case ANY_OBJECT:
-                        return IntMappingType.AnyObjectVirtualSchema;
-
-                    case GROUP:
-                        return IntMappingType.GroupVirtualSchema;
-
-                    case USER:
-                    default:
-                        return IntMappingType.UserVirtualSchema;
-                }
-            }
-
-            @Override
-            public void setIntMappingType(final IntMappingType intMappingType) {
-                // RO instance, nothing to do
-            }
-
-            @Override
-            public String getMandatoryCondition() {
-                return JPAVirSchema.this.getMandatoryCondition();
-            }
-
-            @Override
-            public void setMandatoryCondition(final String condition) {
-                // RO instance, nothing to do
-            }
-
-            @Override
-            public MappingPurpose getPurpose() {
-                return JPAVirSchema.this.isReadonly() ? MappingPurpose.SYNCHRONIZATION : MappingPurpose.BOTH;
-            }
-
-            @Override
-            public void setPurpose(final MappingPurpose purpose) {
-                // RO instance, nothing to do
-            }
-
-            @Override
-            public boolean isConnObjectKey() {
-                return false;
-            }
-
-            @Override
-            public void setConnObjectKey(final boolean connObjectKey) {
-                // RO instance, nothing to do
-            }
-
-            @Override
-            public boolean isPassword() {
-                return false;
-            }
-
-            @Override
-            public void setPassword(final boolean password) {
-                // RO instance, nothing to do
-            }
-
-            @Override
-            public List<String> getMappingItemTransformerClassNames() {
-                return Collections.emptyList();
-            }
-        };
+        return new LinkingMappingItem(this);
     }
 
 }


[30/54] [abbrv] syncope git commit: Managed error messages from Logger stack and managed server down exception, SYNCOPE-158

Posted by fm...@apache.org.
Managed error messages from Logger stack and managed server down exception, SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 462289dce937d9590947d1d9141bd75804288f03
Parents: 5ebdcf7
Author: massi <ma...@tirasa.net>
Authored: Tue Oct 20 17:35:26 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Tue Oct 20 17:35:26 2015 +0200

----------------------------------------------------------------------
 .../apache/syncope/client/cli/SyncopeAdm.java    |  9 ++++++---
 .../client/cli/commands/logger/LoggerCreate.java |  7 ++-----
 .../client/cli/commands/logger/LoggerDelete.java |  7 +++----
 .../client/cli/commands/logger/LoggerList.java   |  3 +--
 .../client/cli/commands/logger/LoggerRead.java   |  7 +++----
 .../client/cli/commands/logger/LoggerUpdate.java | 14 +++++---------
 .../cli/commands/logger/LoggerUpdateAll.java     | 10 +++-------
 .../cli/commands/logger/ResultManager.java       | 19 +++++++++++++++++++
 .../syncope/client/cli/messages/Table.java       |  2 +-
 9 files changed, 43 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/462289dc/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
index e62e818..78e2f54 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
@@ -18,8 +18,9 @@
  */
 package org.apache.syncope.client.cli;
 
+import javax.ws.rs.ProcessingException;
 import org.apache.syncope.client.cli.commands.AbstractCommand;
-import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.commands.logger.ResultManager;
 import org.apache.syncope.client.cli.util.CommandUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,10 +49,12 @@ public final class SyncopeAdm {
             System.out.println(helpMessage());
         } catch (final IllegalArgumentException ex) {
             LOG.error("Error in main", ex);
-            Messages.printMessage(ex.getMessage());
+            new ResultManager().genericError(ex.getMessage());
             if (!ex.getMessage().startsWith("It seems you")) {
                 System.out.println(helpMessage());
             }
+        } catch (final ProcessingException e) {
+            new ResultManager().genericError("Syncope server offline", e.getCause().getMessage());
         }
 
     }
@@ -69,7 +72,7 @@ public final class SyncopeAdm {
                 helpMessageBuilder.append("\n");
             }
         } catch (final IllegalAccessException | IllegalArgumentException | InstantiationException ex) {
-            Messages.printMessage(ex.getMessage());
+            new ResultManager().genericError(ex.getMessage());
         }
 
         return helpMessageBuilder.toString();

http://git-wip-us.apache.org/repos/asf/syncope/blob/462289dc/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
index 1444938..d70aad1 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
@@ -21,8 +21,6 @@ package org.apache.syncope.client.cli.commands.logger;
 import java.util.LinkedList;
 import javax.xml.ws.WebServiceException;
 import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.LoggerTO;
 import org.apache.syncope.common.lib.types.LoggerLevel;
@@ -54,8 +52,7 @@ public class LoggerCreate extends AbstractLoggerCommand {
                     loggerService.update(LoggerType.LOG, loggerTO);
                     loggerTOs.add(loggerTO);
                 } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
-                    Messages.printTypeNotValidMessage(
-                            "logger level", input.firstParameter(), CommandUtils.fromEnumToArray(LoggerLevel.class));
+                    resultManager.typeNotValidError(input.firstParameter());
                     failed = true;
                     break;
                 }
@@ -64,7 +61,7 @@ public class LoggerCreate extends AbstractLoggerCommand {
                 resultManager.fromUpdate(loggerTOs);
             }
         } else {
-            Messages.printCommandOptionMessage(CREATE_HELP_MESSAGE);
+            resultManager.commandOptionError(CREATE_HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/462289dc/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
index 49becd5..44f39ee 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
@@ -21,7 +21,6 @@ package org.apache.syncope.client.cli.commands.logger;
 import java.util.LinkedList;
 import javax.xml.ws.WebServiceException;
 import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.messages.Messages;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.LoggerTO;
 import org.apache.syncope.common.lib.types.LoggerType;
@@ -45,9 +44,9 @@ public class LoggerDelete extends AbstractLoggerCommand {
                     loggerService.delete(LoggerType.LOG, parameter);
                 } catch (final WebServiceException | SyncopeClientException ex) {
                     if (ex.getMessage().startsWith("NotFound")) {
-                        Messages.printNofFoundMessage("Logger", parameter);
+                        resultManager.notFoundError(parameter);
                     } else {
-                        Messages.printMessage(ex.getMessage());
+                        resultManager.genericError(ex.getMessage());
                     }
                     failed = true;
                 }
@@ -56,7 +55,7 @@ public class LoggerDelete extends AbstractLoggerCommand {
                 resultManager.fromDelete(loggerTOs);
             }
         } else {
-            Messages.printCommandOptionMessage(DELETE_HELP_MESSAGE);
+            resultManager.commandOptionError(DELETE_HELP_MESSAGE);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/462289dc/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
index 78d2ced..bee7e7c 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.client.cli.commands.logger;
 
 import java.util.LinkedList;
-import org.apache.syncope.client.cli.messages.Messages;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.types.LoggerType;
 
@@ -32,7 +31,7 @@ public class LoggerList extends AbstractLoggerCommand {
         try {
             resultManager.fromList(new LinkedList<>(loggerService.list(LoggerType.LOG)));
         } catch (final SyncopeClientException ex) {
-            Messages.printMessage("Error: " + ex.getMessage());
+            resultManager.genericError("Error: " + ex.getMessage());
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/462289dc/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
index 4d33191..3cbca46 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
@@ -21,7 +21,6 @@ package org.apache.syncope.client.cli.commands.logger;
 import java.util.LinkedList;
 import javax.xml.ws.WebServiceException;
 import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.messages.Messages;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.LoggerTO;
 import org.apache.syncope.common.lib.types.LoggerType;
@@ -45,9 +44,9 @@ public class LoggerRead extends AbstractLoggerCommand {
                     loggerTOs.add(loggerService.read(LoggerType.LOG, parameter));
                 } catch (final SyncopeClientException | WebServiceException ex) {
                     if (ex.getMessage().startsWith("NotFound")) {
-                        Messages.printNofFoundMessage("Logger", parameter);
+                        resultManager.notFoundError(parameter);
                     } else {
-                        Messages.printMessage("Error: " + ex.getMessage());
+                        resultManager.genericError("Error: " + ex.getMessage());
                     }
                     failed = true;
                     break;
@@ -57,7 +56,7 @@ public class LoggerRead extends AbstractLoggerCommand {
                 resultManager.fromRead(loggerTOs);
             }
         } else {
-            Messages.printCommandOptionMessage(READ_HELP_MESSAGE);
+            resultManager.commandOptionError(READ_HELP_MESSAGE);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/462289dc/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
index fccfe72..d309c4c 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
@@ -21,8 +21,6 @@ package org.apache.syncope.client.cli.commands.logger;
 import java.util.LinkedList;
 import javax.xml.ws.WebServiceException;
 import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.LoggerTO;
 import org.apache.syncope.common.lib.types.LoggerLevel;
@@ -54,15 +52,13 @@ public class LoggerUpdate extends AbstractLoggerCommand {
                     loggerTOs.add(loggerTO);
                 } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
                     if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                        Messages.printTypeNotValidMessage(
-                                "logger level",
-                                input.firstParameter(), CommandUtils.fromEnumToArray(LoggerLevel.class));
+                        resultManager.typeNotValidError(input.firstParameter());
                     } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
-                        Messages.printMessage(ex.getMessage(), UPDATE_HELP_MESSAGE);
+                        resultManager.genericError(ex.getMessage(), UPDATE_HELP_MESSAGE);
                     } else if (ex.getMessage().startsWith("NotFound")) {
-                        Messages.printNofFoundMessage("Logger", parameter);
+                        resultManager.notFoundError(parameter);
                     } else {
-                        Messages.printMessage(ex.getMessage(), UPDATE_HELP_MESSAGE);
+                        resultManager.genericError(ex.getMessage(), UPDATE_HELP_MESSAGE);
                     }
                     failed = true;
                     break;
@@ -72,7 +68,7 @@ public class LoggerUpdate extends AbstractLoggerCommand {
                 resultManager.fromUpdate(loggerTOs);
             }
         } else {
-            Messages.printCommandOptionMessage(UPDATE_HELP_MESSAGE);
+            resultManager.commandOptionError(UPDATE_HELP_MESSAGE);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/462289dc/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
index b0ee25c..3393ae4 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
@@ -21,8 +21,6 @@ package org.apache.syncope.client.cli.commands.logger;
 import java.util.LinkedList;
 import javax.xml.ws.WebServiceException;
 import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.LoggerTO;
 import org.apache.syncope.common.lib.types.LoggerLevel;
@@ -49,11 +47,9 @@ public class LoggerUpdateAll extends AbstractLoggerCommand {
                     loggerTOs.add(loggerTO);
                 } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
                     if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                        Messages.printTypeNotValidMessage(
-                                "logger level",
-                                input.firstParameter(), CommandUtils.fromEnumToArray(LoggerLevel.class));
+                        resultManager.typeNotValidError(input.firstParameter());
                     } else {
-                        Messages.printMessage(ex.getMessage(), UPDATE_ALL_HELP_MESSAGE);
+                        resultManager.genericError(ex.getMessage(), UPDATE_ALL_HELP_MESSAGE);
                     }
                     failed = true;
                     break;
@@ -63,7 +59,7 @@ public class LoggerUpdateAll extends AbstractLoggerCommand {
                 resultManager.fromUpdate(loggerTOs);
             }
         } else {
-            Messages.printCommandOptionMessage(UPDATE_ALL_HELP_MESSAGE);
+            resultManager.commandOptionError(UPDATE_ALL_HELP_MESSAGE);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/462289dc/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java
index 102ff74..e993eb7 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java
@@ -20,11 +20,30 @@ package org.apache.syncope.client.cli.commands.logger;
 
 import java.util.Arrays;
 import java.util.LinkedList;
+import org.apache.syncope.client.cli.messages.Messages;
 import org.apache.syncope.client.cli.messages.Table;
+import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.to.LoggerTO;
+import org.apache.syncope.common.lib.types.LoggerLevel;
 
 public class ResultManager {
 
+    public void notFoundError(final String parameter) {
+        Messages.printNofFoundMessage("Logger", parameter);
+    }
+
+    public void typeNotValidError(final String parameter) {
+        Messages.printTypeNotValidMessage("logger level", parameter, CommandUtils.fromEnumToArray(LoggerLevel.class));
+    }
+
+    public void commandOptionError(final String message) {
+        Messages.printCommandOptionMessage(message);
+    }
+
+    public void genericError(final String... messages) {
+        Messages.printMessage(messages);
+    }
+
     public void fromList(final LinkedList<LoggerTO> loggerTOs) {
         fromCommandToView("list loggers", "level", loggerTOs);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/462289dc/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
index 4f22980..8a28965 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
@@ -128,7 +128,7 @@ public final class Table {
         System.out.format(TABLE_TITLE_FORMAT, StringUtils.center(" ", tableWidth - 6));
     }
 
-    public void printHeaders() {
+    private void printHeaders() {
         printColumnSpace();
 
         for (int h = 0; h < columnsNumber; h++) {


[26/54] [abbrv] syncope git commit: deleted class

Posted by fm...@apache.org.
deleted class


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

Branch: refs/heads/SYNCOPE-156
Commit: 4d71ff3c5d4d8f6df8fefb4647f79cd02dfd980d
Parents: f8d46d3
Author: massi <ma...@tirasa.net>
Authored: Tue Oct 20 14:59:00 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Tue Oct 20 14:59:00 2015 +0200

----------------------------------------------------------------------
 .../client/cli/commands/LoggerCommand.java      | 271 -------------------
 1 file changed, 271 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/4d71ff3c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
deleted file mode 100644
index 4c6caf5..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * 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.cli.commands;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.ws.WebServiceException;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.cli.Command;
-import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.SyncopeServices;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.util.CommandUtils;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.LoggerTO;
-import org.apache.syncope.common.lib.types.LoggerLevel;
-import org.apache.syncope.common.lib.types.LoggerType;
-import org.apache.syncope.common.rest.api.service.LoggerService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Command(name = "logger")
-public class LoggerCommand extends AbstractCommand {
-
-    private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
-
-    private static final String HELP_MESSAGE = "Usage: logger [options]\n"
-            + "  Options:\n"
-            + "    --help \n"
-            + "    --list \n"
-            + "    --read \n"
-            + "       Syntax: --read {LOG-NAME} {LOG-NAME} [...]\n"
-            + "    --update \n"
-            + "       Syntax: --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]\n"
-            + "    --update-all \n"
-            + "       Syntax: --update-all {LOG-LEVEL} \n"
-            + "    --create \n"
-            + "       Syntax: --create {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]\n"
-            + "    --delete \n"
-            + "       Syntax: --delete {LOG-NAME} {LOG-NAME} [...]";
-
-    @Override
-    public void execute(final Input input) {
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
-        final String[] parameters = input.getParameters();
-
-        if (StringUtils.isBlank(input.getOption())) {
-            input.setOption(Options.HELP.getOptionName());
-        }
-
-        final LoggerService loggerService = SyncopeServices.get(LoggerService.class);
-        switch (Options.fromName(input.getOption())) {
-            case LIST:
-                try {
-                    for (final LoggerTO loggerTO : loggerService.list(LoggerType.LOG)) {
-                        System.out.println(" - " + loggerTO.getKey() + " -> " + loggerTO.getLevel());
-                        System.out.println("");
-                    }
-                } catch (final SyncopeClientException ex) {
-                    Messages.printMessage("Error: " + ex.getMessage());
-                }
-                break;
-            case READ:
-                final String readErrorMessage = "logger --read {LOG-NAME} {LOG-NAME} [...]";
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            final LoggerTO loggerTO = loggerService.read(LoggerType.LOG, parameter);
-                            System.out.println("\n - Logger");
-                            System.out.println("   - key: " + loggerTO.getKey());
-                            System.out.println("   - level: " + loggerTO.getLevel());
-                            System.out.println("");
-                        } catch (final SyncopeClientException | WebServiceException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Logger", parameter);
-                            } else {
-                                Messages.printMessage("Error: " + ex.getMessage());
-                            }
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(readErrorMessage);
-                }
-                break;
-            case UPDATE:
-                final String updateErrorMessage = "logger --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
-
-                if (parameters.length >= 1) {
-                    Input.PairParameter pairParameter;
-                    for (final String parameter : parameters) {
-                        try {
-                            pairParameter = input.toPairParameter(parameter);
-                            final LoggerTO loggerTO = loggerService.read(LoggerType.LOG, pairParameter.getKey());
-                            loggerTO.setLevel(LoggerLevel.valueOf(pairParameter.getValue()));
-                            loggerService.update(LoggerType.LOG, loggerTO);
-                            System.out.
-                                    println("\n - Logger " + loggerTO.getKey() + " updated");
-                            System.out.println("   - new level: " + loggerTO.getLevel());
-                            System.out.println("");
-                        } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
-                            if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                                Messages.printTypeNotValidMessage(
-                                        "logger level", input.firstParameter(),
-                                        CommandUtils.fromEnumToArray(LoggerLevel.class));
-                            } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
-                                Messages.printMessage(ex.getMessage(), updateErrorMessage);
-                            } else if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Logger", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage(), updateErrorMessage);
-                            }
-                            break;
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(updateErrorMessage);
-                }
-                break;
-            case UPDATE_ALL:
-                final String updateAllErrorMessage = "logger --update-all {LOG-LEVEL}";
-
-                if (parameters.length == 1) {
-                    for (final LoggerTO loggerTO : loggerService.list(LoggerType.LOG)) {
-                        try {
-                            loggerTO.setLevel(LoggerLevel.valueOf(parameters[0]));
-                            loggerService.update(LoggerType.LOG, loggerTO);
-                            System.out.
-                                    println("\n - Logger " + loggerTO.getKey() + " updated");
-                            System.out.println("   - new level: " + loggerTO.getLevel());
-                            System.out.println("");
-                        } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
-                            if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                                Messages.printTypeNotValidMessage(
-                                        "logger level", input.firstParameter(),
-                                        CommandUtils.fromEnumToArray(LoggerLevel.class));
-                            } else {
-                                Messages.printMessage(ex.getMessage(), updateAllErrorMessage);
-                            }
-                            break;
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(updateAllErrorMessage);
-                }
-                break;
-            case CREATE:
-                final String createErrorMessage = "logger --create {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
-
-                if (parameters.length >= 1) {
-                    Input.PairParameter pairParameter;
-                    LoggerTO loggerTO;
-                    for (final String parameter : parameters) {
-                        loggerTO = new LoggerTO();
-                        try {
-                            pairParameter = input.toPairParameter(parameter);
-                            loggerTO.setKey(pairParameter.getKey());
-                            loggerTO.setLevel(LoggerLevel.valueOf(pairParameter.getValue()));
-                            loggerService.update(LoggerType.LOG, loggerTO);
-                            System.out.
-                                    println("\n - Logger " + loggerTO.getKey() + " updated");
-                            System.out.println("   - level: " + loggerTO.getLevel());
-                            System.out.println("");
-                        } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
-                            Messages.printTypeNotValidMessage(
-                                    "logger level", input.firstParameter(),
-                                    CommandUtils.fromEnumToArray(LoggerLevel.class));
-                            break;
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(createErrorMessage);
-                }
-                break;
-            case DELETE:
-                final String deleteErrorMessage = "logger --delete {LOG-NAME} {LOG-NAME} [...]";
-
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            loggerService.delete(LoggerType.LOG, parameter);
-                            Messages.printDeletedMessage("Logger", parameter);
-                        } catch (final WebServiceException | SyncopeClientException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Logger", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(deleteErrorMessage);
-                }
-                break;
-            case HELP:
-                System.out.println(HELP_MESSAGE);
-                break;
-            default:
-                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
-        }
-    }
-
-    @Override
-    public String getHelpMessage() {
-        return HELP_MESSAGE;
-    }
-
-    private enum Options {
-
-        HELP("--help"),
-        LIST("--list"),
-        READ("--read"),
-        UPDATE("--update"),
-        UPDATE_ALL("--update-all"),
-        CREATE("--create"),
-        DELETE("--delete");
-
-        private final String optionName;
-
-        Options(final String optionName) {
-            this.optionName = optionName;
-        }
-
-        public String getOptionName() {
-            return optionName;
-        }
-
-        public boolean equalsOptionName(final String otherName) {
-            return (otherName == null) ? false : optionName.equals(otherName);
-        }
-
-        public static Options fromName(final String name) {
-            Options optionToReturn = HELP;
-            for (final Options option : Options.values()) {
-                if (option.equalsOptionName(name)) {
-                    optionToReturn = option;
-                }
-            }
-            return optionToReturn;
-        }
-
-        public static List<String> toList() {
-            final List<String> options = new ArrayList<>();
-            for (final Options value : values()) {
-                options.add(value.getOptionName());
-            }
-            return options;
-        }
-    }
-
-}


[23/54] [abbrv] syncope git commit: introduced table view to print results (logger stack), SYNCOPE-158

Posted by fm...@apache.org.
introduced table view to print results (logger stack), SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 47392366e6f2cd04a8d016ef74f2bda408c86fe4
Parents: 2a99db9
Author: massi <ma...@tirasa.net>
Authored: Tue Oct 20 14:53:16 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Tue Oct 20 14:53:16 2015 +0200

----------------------------------------------------------------------
 .../org/apache/syncope/client/cli/Input.java    |   4 +
 .../apache/syncope/client/cli/SyncopeAdm.java   |   8 +
 .../client/cli/commands/AbstractCommand.java    |  19 --
 .../cli/commands/ConfigurationCommand.java      | 124 ++++-----
 .../client/cli/commands/DomainCommand.java      |   1 +
 .../client/cli/commands/HelpCommand.java        |   4 +-
 .../client/cli/commands/InfoCommand.java        |   7 +-
 .../client/cli/commands/LoggerCommand.java      | 267 -------------------
 .../client/cli/commands/PolicyCommand.java      |   3 +-
 .../client/cli/commands/ReportCommand.java      |   3 +-
 .../client/cli/commands/SchemaCommand.java      |  16 +-
 .../client/cli/commands/TaskCommand.java        |   6 +-
 .../cli/commands/install/InstallCommand.java    |   2 +-
 .../commands/logger/AbstractLoggerCommand.java  |  30 +++
 .../cli/commands/logger/LoggerCommand.java      | 128 +++++++++
 .../cli/commands/logger/LoggerCreate.java       |  71 +++++
 .../cli/commands/logger/LoggerDelete.java       |  63 +++++
 .../client/cli/commands/logger/LoggerList.java  |  38 +++
 .../client/cli/commands/logger/LoggerRead.java  |  63 +++++
 .../cli/commands/logger/LoggerUpdate.java       |  78 ++++++
 .../cli/commands/logger/LoggerUpdateAll.java    |  69 +++++
 .../cli/commands/logger/ResultManager.java      |  60 +++++
 .../syncope/client/cli/messages/Messages.java   |  14 +-
 .../syncope/client/cli/messages/Table.java      | 190 +++++++++++++
 .../client/cli/messages/TwoColumnTable.java     | 262 ++++++++++++++++++
 .../syncope/client/cli/util/CommandUtils.java   |  20 +-
 26 files changed, 1172 insertions(+), 378 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/Input.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/Input.java b/client/cli/src/main/java/org/apache/syncope/client/cli/Input.java
index 6e2aeeb..c53eefd 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/Input.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/Input.java
@@ -72,6 +72,10 @@ public class Input {
         return parameters[parameters.length - 1];
     }
 
+    public int parameterNumber() {
+        return parameters.length;
+    }
+
     public PairParameter toPairParameter(final String parameter) throws IllegalArgumentException {
         if (!parameter.contains("=")) {
             throw new IllegalArgumentException("Parameter syntax error!");

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
index d503498..e62e818 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/SyncopeAdm.java
@@ -35,6 +35,14 @@ public final class SyncopeAdm {
             ArgsManager.validator(args);
             final Input input = new Input(args);
             final AbstractCommand command = input.getCommand();
+
+            LOG.debug("Command: {}", command.getClass().getAnnotation(Command.class).name());
+            LOG.debug("Option: {}", input.getOption());
+            LOG.debug("Parameters:");
+            for (final String parameter : input.getParameters()) {
+                LOG.debug("   > " + parameter);
+            }
+
             command.execute(input);
         } catch (final IllegalAccessException | InstantiationException e) {
             System.out.println(helpMessage());

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/AbstractCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/AbstractCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/AbstractCommand.java
index 7cee202..6a03556 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/AbstractCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/AbstractCommand.java
@@ -18,30 +18,11 @@
  */
 package org.apache.syncope.client.cli.commands;
 
-import java.util.List;
 import org.apache.syncope.client.cli.Input;
 
 public abstract class AbstractCommand {
 
     public abstract void execute(final Input input);
 
-    protected String helpMessage(final String command, final List<String> options) {
-        final StringBuilder helpMessageBuilder = new StringBuilder(String.format("Usage: %s [options]\n", command));
-        helpMessageBuilder.append("  Options:\n");
-        for (final String option : options) {
-            helpMessageBuilder.append("    ").append(option).append("\n");
-        }
-        return helpMessageBuilder.toString();
-    }
-
     public abstract String getHelpMessage();
-
-    protected static String[] fromEnumToArray(final Class<? extends Enum<?>> enumClass) {
-        final String[] types = new String[enumClass.getFields().length];
-        for (int i = 0; i < enumClass.getFields().length; i++) {
-            types[i] = enumClass.getFields()[i].getName();
-
-        }
-        return types;
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
index ee225d7..01f6d23 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ConfigurationCommand.java
@@ -22,7 +22,11 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.SequenceInputStream;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerException;
@@ -32,6 +36,7 @@ import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.messages.TwoColumnTable;
 import org.apache.syncope.client.cli.util.XMLUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AttrTO;
@@ -51,13 +56,11 @@ public class ConfigurationCommand extends AbstractCommand {
     private static final String HELP_MESSAGE = "Usage: configuration [options]\n"
             + "  Options:\n"
             + "    --help \n"
-            + "    --list \n"
+            + "    --get \n"
             + "    --read \n"
             + "       Syntax: --read {CONF-NAME} {CONF-NAME} [...] \n"
             + "    --update \n"
             + "       Syntax: --update {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]\n"
-            + "    --create \n"
-            + "       Syntax: --create {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]\n"
             + "    --delete \n"
             + "       Syntax: --delete {CONF-NAME} {CONF-NAME} [...]\n"
             + "    --export \n"
@@ -80,32 +83,10 @@ public class ConfigurationCommand extends AbstractCommand {
 
         final ConfigurationService configurationService = SyncopeServices.get(ConfigurationService.class);
         switch (Options.fromName(input.getOption())) {
-            case LIST:
+            case GET:
                 try {
                     final ConfTO confTO = configurationService.list();
-                    System.out.println("\n - Configuration key: " + confTO.getKey());
-                    System.out.println("");
-                    System.out.println("Plain attributes");
-                    for (final AttrTO attrTO : confTO.getPlainAttrMap().values()) {
-                        System.out.println(" - Conf key: " + attrTO.getSchema());
-                        System.out.println("    - value(s): " + attrTO.getValues());
-                        System.out.println("    - readonly: " + attrTO.isReadonly());
-                    }
-                    System.out.println("");
-                    System.out.println("Derived attributes");
-                    for (final AttrTO attrTO : confTO.getDerAttrMap().values()) {
-                        System.out.println(" - Conf key: " + attrTO.getSchema());
-                        System.out.println("    - value(s): " + attrTO.getValues());
-                        System.out.println("    - readonly: " + attrTO.isReadonly());
-                    }
-                    System.out.println("");
-                    System.out.println("Virtual attributes");
-                    for (final AttrTO attrTO : confTO.getVirAttrMap().values()) {
-                        System.out.println(" - Conf key: " + attrTO.getSchema());
-                        System.out.println("    - value(s): " + attrTO.getValues());
-                        System.out.println("    - readonly: " + attrTO.isReadonly());
-                    }
-                    System.out.println("");
+                    toTable("Syncope configuration", "attribute", "value", confTO.getPlainAttrs());
                 } catch (final Exception ex) {
                     Messages.printMessage(ex.getMessage());
                     break;
@@ -114,23 +95,24 @@ public class ConfigurationCommand extends AbstractCommand {
             case READ:
                 final String readErrorMessage = "configuration --read {CONF-NAME} {CONF-NAME} [...]";
                 if (parameters.length >= 1) {
-                    AttrTO attrTO;
+                    final Set<AttrTO> attrList = new HashSet<>();
+                    boolean failed = false;
                     for (final String parameter : parameters) {
                         try {
-                            attrTO = configurationService.get(parameter);
-                            System.out.println("\n - Conf key: " + attrTO.getSchema());
-                            System.out.println("    - value(s): " + attrTO.getValues());
-                            System.out.println("    - readonly: " + attrTO.isReadonly());
-                            System.out.println("");
+                            attrList.add(configurationService.get(parameter));
                         } catch (final SyncopeClientException | WebServiceException ex) {
                             if (ex.getMessage().startsWith("NotFound")) {
                                 Messages.printNofFoundMessage("Logger", parameter);
                             } else {
                                 Messages.printMessage(ex.getMessage());
                             }
+                            failed = true;
                             break;
                         }
                     }
+                    if (!failed) {
+                        toTable("Read result", "attribute", "value", attrList);
+                    }
                 } else {
                     Messages.printCommandOptionMessage(readErrorMessage);
                 }
@@ -141,6 +123,8 @@ public class ConfigurationCommand extends AbstractCommand {
                 if (parameters.length >= 1) {
                     Input.PairParameter pairParameter = null;
                     AttrTO attrTO;
+                    final Set<AttrTO> attrList = new HashSet<>();
+                    boolean failed = false;
                     for (final String parameter : parameters) {
                         try {
                             pairParameter = input.toPairParameter(parameter);
@@ -148,12 +132,10 @@ public class ConfigurationCommand extends AbstractCommand {
                             attrTO.getValues().clear();
                             attrTO.getValues().add(pairParameter.getValue());
                             configurationService.set(attrTO);
-                            System.out.println("\n - Conf key " + attrTO.getSchema() + " updated. New value is:");
-                            System.out.println("    - value(s): " + attrTO.getValues());
-                            System.out.println("    - readonly: " + attrTO.isReadonly());
-                            System.out.println("");
+                            attrList.add(attrTO);
                         } catch (final IllegalArgumentException ex) {
                             Messages.printMessage(ex.getMessage(), updateErrorMessage);
+                            failed = true;
                             break;
                         } catch (final SyncopeClientException | WebServiceException ex) {
                             if (ex.getMessage().startsWith("NotFound")) {
@@ -165,45 +147,15 @@ public class ConfigurationCommand extends AbstractCommand {
                             } else {
                                 Messages.printMessage(ex.getMessage());
                             }
+                            failed = true;
                             break;
                         }
                     }
-                } else {
-                    Messages.printCommandOptionMessage(updateErrorMessage);
-                }
-                break;
-            case CREATE:
-                final String createErrorMessage
-                        = "configuration --create {CONF-NAME}={CONF-VALUE} {CONF-NAME}={CONF-VALUE} [...]";
-                if (parameters.length >= 1) {
-                    Input.PairParameter pairParameter = null;
-                    AttrTO attrTO;
-                    for (final String parameter : parameters) {
-                        try {
-                            pairParameter = input.toPairParameter(parameter);
-                            attrTO = new AttrTO();
-                            attrTO.setSchema(pairParameter.getKey());
-                            attrTO.getValues().add(pairParameter.getValue());
-                            configurationService.set(attrTO);
-                            System.out.println("\n - Conf key " + attrTO.getSchema() + " created. Value is:");
-                            System.out.println("    - value(s): " + attrTO.getValues());
-                            System.out.println("    - readonly: " + attrTO.isReadonly());
-                            System.out.println("");
-                        } catch (final IllegalArgumentException ex) {
-                            Messages.printMessage(ex.getMessage(), createErrorMessage);
-                            break;
-                        } catch (final SyncopeClientException | WebServiceException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Configuration", pairParameter.getKey());
-                                System.out.println("Create it before.");
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                            break;
-                        }
+                    if (!failed) {
+                        toTable("updated attribute", "attribute", "new value", attrList);
                     }
                 } else {
-                    Messages.printCommandOptionMessage(createErrorMessage);
+                    Messages.printCommandOptionMessage(updateErrorMessage);
                 }
                 break;
             case DELETE:
@@ -269,6 +221,33 @@ public class ConfigurationCommand extends AbstractCommand {
         }
     }
 
+    private void toTable(final String tableTitle,
+            final String firstHeader,
+            final String seconHeader,
+            final Set<AttrTO> attrList) {
+        int maxFirstColumnLenght = 0;
+        int maxSecondColumnLenght = 0;
+        final Map<String, String> attributes = new HashMap<>();
+        for (final AttrTO attrTO : attrList) {
+            String value = attrTO.getValues().toString();
+            value = value.substring(0, value.length() - 1);
+            value = value.substring(1, value.length());
+            attributes.put(attrTO.getSchema(), value);
+            if (attrTO.getSchema().length() > maxFirstColumnLenght) {
+                maxFirstColumnLenght = attrTO.getSchema().length();
+            }
+
+            if (value.length() > maxSecondColumnLenght) {
+                maxSecondColumnLenght = attrTO.getSchema().length();
+            }
+        }
+        final TwoColumnTable loggerTableResult = new TwoColumnTable(
+                tableTitle,
+                firstHeader, maxFirstColumnLenght,
+                seconHeader, maxSecondColumnLenght);
+        loggerTableResult.printTable(attributes);
+    }
+
     @Override
     public String getHelpMessage() {
         return HELP_MESSAGE;
@@ -277,10 +256,9 @@ public class ConfigurationCommand extends AbstractCommand {
     private enum Options {
 
         HELP("--help"),
-        LIST("--list"),
+        GET("--get"),
         READ("--read"),
         UPDATE("--update"),
-        CREATE("--create"),
         DELETE("--delete"),
         EXPORT("--export");
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
index a2a0977..e22359d 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/DomainCommand.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.client.cli.commands;
 
+import org.apache.syncope.client.cli.commands.logger.LoggerCommand;
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.commons.lang3.StringUtils;

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
index 85b7d73..e415e14 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/HelpCommand.java
@@ -63,14 +63,14 @@ public class HelpCommand extends AbstractCommand {
                 }
                 break;
             default:
-                Messages.printDefaultMessage(input.getOption(), helpMessage("info", Options.toList()));
+                Messages.printDefaultMessage(input.getOption(), CommandUtils.helpMessage("info", Options.toList()));
                 break;
         }
     }
 
     @Override
     public String getHelpMessage() {
-        return helpMessage("help", Options.toList());
+        return CommandUtils.helpMessage("help", Options.toList());
     }
 
     private enum Options {

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
index 07bb952..1636c3d 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/InfoCommand.java
@@ -25,6 +25,7 @@ import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.to.SyncopeTO;
 import org.apache.syncope.common.rest.api.service.SyncopeService;
 import org.slf4j.Logger;
@@ -264,17 +265,17 @@ public class InfoCommand extends AbstractCommand {
                 }
                 break;
             case HELP:
-                System.out.println(helpMessage("info", Options.toList()));
+                System.out.println(CommandUtils.helpMessage("info", Options.toList()));
                 break;
             default:
-                Messages.printDefaultMessage(input.getOption(), helpMessage("info", Options.toList()));
+                Messages.printDefaultMessage(input.getOption(), CommandUtils.helpMessage("info", Options.toList()));
                 break;
         }
     }
 
     @Override
     public String getHelpMessage() {
-        return helpMessage("info", Options.toList());
+        return CommandUtils.helpMessage("info", Options.toList());
     }
 
     private enum Options {

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
deleted file mode 100644
index 6c11c6f..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/LoggerCommand.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * 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.cli.commands;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.ws.WebServiceException;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.cli.Command;
-import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.SyncopeServices;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.LoggerTO;
-import org.apache.syncope.common.lib.types.LoggerLevel;
-import org.apache.syncope.common.lib.types.LoggerType;
-import org.apache.syncope.common.rest.api.service.LoggerService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Command(name = "logger")
-public class LoggerCommand extends AbstractCommand {
-
-    private static final Logger LOG = LoggerFactory.getLogger(LoggerCommand.class);
-
-    private static final String HELP_MESSAGE = "Usage: logger [options]\n"
-            + "  Options:\n"
-            + "    --help \n"
-            + "    --list \n"
-            + "    --read \n"
-            + "       Syntax: --read {LOG-NAME} {LOG-NAME} [...]\n"
-            + "    --update \n"
-            + "       Syntax: --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]\n"
-            + "    --update-all \n"
-            + "       Syntax: --update-all {LOG-LEVEL} \n"
-            + "    --create \n"
-            + "       Syntax: --create {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]\n"
-            + "    --delete \n"
-            + "       Syntax: --delete {LOG-NAME} {LOG-NAME} [...]";
-
-    @Override
-    public void execute(final Input input) {
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
-        final String[] parameters = input.getParameters();
-
-        if (StringUtils.isBlank(input.getOption())) {
-            input.setOption(Options.HELP.getOptionName());
-        }
-
-        final LoggerService loggerService = SyncopeServices.get(LoggerService.class);
-        switch (Options.fromName(input.getOption())) {
-            case LIST:
-                try {
-                    for (final LoggerTO loggerTO : loggerService.list(LoggerType.LOG)) {
-                        System.out.println(" - " + loggerTO.getKey() + " -> " + loggerTO.getLevel());
-                        System.out.println("");
-                    }
-                } catch (final SyncopeClientException ex) {
-                    Messages.printMessage("Error: " + ex.getMessage());
-                }
-                break;
-            case READ:
-                final String readErrorMessage = "logger --read {LOG-NAME} {LOG-NAME} [...]";
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            final LoggerTO loggerTO = loggerService.read(LoggerType.LOG, parameter);
-                            System.out.println("\n - Logger");
-                            System.out.println("   - key: " + loggerTO.getKey());
-                            System.out.println("   - level: " + loggerTO.getLevel());
-                            System.out.println("");
-                        } catch (final SyncopeClientException | WebServiceException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Logger", parameter);
-                            } else {
-                                Messages.printMessage("Error: " + ex.getMessage());
-                            }
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(readErrorMessage);
-                }
-                break;
-            case UPDATE:
-                final String updateErrorMessage = "logger --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
-
-                if (parameters.length >= 1) {
-                    Input.PairParameter pairParameter;
-                    for (final String parameter : parameters) {
-                        try {
-                            pairParameter = input.toPairParameter(parameter);
-                            final LoggerTO loggerTO = loggerService.read(LoggerType.LOG, pairParameter.getKey());
-                            loggerTO.setLevel(LoggerLevel.valueOf(pairParameter.getValue()));
-                            loggerService.update(LoggerType.LOG, loggerTO);
-                            System.out.
-                                    println("\n - Logger " + loggerTO.getKey() + " updated");
-                            System.out.println("   - new level: " + loggerTO.getLevel());
-                            System.out.println("");
-                        } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
-                            if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                                Messages.printTypeNotValidMessage(
-                                        "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
-                            } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
-                                Messages.printMessage(ex.getMessage(), updateErrorMessage);
-                            } else if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Logger", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage(), updateErrorMessage);
-                            }
-                            break;
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(updateErrorMessage);
-                }
-                break;
-            case UPDATE_ALL:
-                final String updateAllErrorMessage = "logger --update-all {LOG-LEVEL}";
-
-                if (parameters.length == 1) {
-                    for (final LoggerTO loggerTO : loggerService.list(LoggerType.LOG)) {
-                        try {
-                            loggerTO.setLevel(LoggerLevel.valueOf(parameters[0]));
-                            loggerService.update(LoggerType.LOG, loggerTO);
-                            System.out.
-                                    println("\n - Logger " + loggerTO.getKey() + " updated");
-                            System.out.println("   - new level: " + loggerTO.getLevel());
-                            System.out.println("");
-                        } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
-                            if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
-                                Messages.printTypeNotValidMessage(
-                                        "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
-                            } else {
-                                Messages.printMessage(ex.getMessage(), updateAllErrorMessage);
-                            }
-                            break;
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(updateAllErrorMessage);
-                }
-                break;
-            case CREATE:
-                final String createErrorMessage = "logger --create {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
-
-                if (parameters.length >= 1) {
-                    Input.PairParameter pairParameter;
-                    LoggerTO loggerTO;
-                    for (final String parameter : parameters) {
-                        loggerTO = new LoggerTO();
-                        try {
-                            pairParameter = input.toPairParameter(parameter);
-                            loggerTO.setKey(pairParameter.getKey());
-                            loggerTO.setLevel(LoggerLevel.valueOf(pairParameter.getValue()));
-                            loggerService.update(LoggerType.LOG, loggerTO);
-                            System.out.
-                                    println("\n - Logger " + loggerTO.getKey() + " updated");
-                            System.out.println("   - level: " + loggerTO.getLevel());
-                            System.out.println("");
-                        } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
-                            Messages.printTypeNotValidMessage(
-                                    "logger level", input.firstParameter(), fromEnumToArray(LoggerLevel.class));
-                            break;
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(createErrorMessage);
-                }
-                break;
-            case DELETE:
-                final String deleteErrorMessage = "logger --delete {LOG-NAME} {LOG-NAME} [...]";
-
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            loggerService.delete(LoggerType.LOG, parameter);
-                            Messages.printDeletedMessage("Logger", parameter);
-                        } catch (final WebServiceException | SyncopeClientException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Logger", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(deleteErrorMessage);
-                }
-                break;
-            case HELP:
-                System.out.println(HELP_MESSAGE);
-                break;
-            default:
-                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
-        }
-    }
-
-    @Override
-    public String getHelpMessage() {
-        return HELP_MESSAGE;
-    }
-
-    private enum Options {
-
-        HELP("--help"),
-        LIST("--list"),
-        READ("--read"),
-        UPDATE("--update"),
-        UPDATE_ALL("--update-all"),
-        CREATE("--create"),
-        DELETE("--delete");
-
-        private final String optionName;
-
-        private Options(final String optionName) {
-            this.optionName = optionName;
-        }
-
-        public String getOptionName() {
-            return optionName;
-        }
-
-        public boolean equalsOptionName(final String otherName) {
-            return (otherName == null) ? false : optionName.equals(otherName);
-        }
-
-        public static Options fromName(final String name) {
-            Options optionToReturn = HELP;
-            for (final Options option : Options.values()) {
-                if (option.equalsOptionName(name)) {
-                    optionToReturn = option;
-                }
-            }
-            return optionToReturn;
-        }
-
-        public static List<String> toList() {
-            final List<String> options = new ArrayList<>();
-            for (final Options value : values()) {
-                options.add(value.getOptionName());
-            }
-            return options;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
index a69be18..28c528e 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
@@ -26,6 +26,7 @@ import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
 import org.apache.syncope.common.lib.types.PolicyType;
@@ -78,7 +79,7 @@ public class PolicyCommand extends AbstractCommand {
                         Messages.printMessage(ex.getMessage());
                     } catch (final IllegalArgumentException ex) {
                         Messages.printTypeNotValidMessage(
-                                "policy", input.firstParameter(), fromEnumToArray(PolicyType.class));
+                                "policy", input.firstParameter(), CommandUtils.fromEnumToArray(PolicyType.class));
                     }
                 } else {
                     Messages.printCommandOptionMessage(listPolicyErrorMessage);

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
index 2178d22..935e4f1 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/ReportCommand.java
@@ -31,6 +31,7 @@ import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.client.cli.util.XMLUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.ReportExecTO;
@@ -283,7 +284,7 @@ public class ReportCommand extends AbstractCommand {
                         } catch (final IllegalArgumentException ex) {
                             Messages.printTypeNotValidMessage(
                                     "format", input.firstParameter(),
-                                    fromEnumToArray(ReportExecExportFormat.class));
+                                    CommandUtils.fromEnumToArray(ReportExecExportFormat.class));
                         }
                         break;
                     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
index 7cb9ca1..bd3ffff 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/SchemaCommand.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.client.cli.commands;
 
-import static org.apache.syncope.client.cli.commands.AbstractCommand.fromEnumToArray;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -29,6 +27,7 @@ import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AbstractSchemaTO;
 import org.apache.syncope.common.lib.to.DerSchemaTO;
@@ -51,10 +50,13 @@ public class SchemaCommand extends AbstractCommand {
             + "    --list-plain\n"
             + "    --list-derived\n"
             + "    --list-virtual\n"
-            + "    --list {SCHEMA-TYPE}\n"
-            + "       Schema type: PLAIN / DERIVED / VIRTUAL";
+            + "    --read {SCHEMA-TYPE} {SCHEMA-KEY}\n"
+            + "        Schema type: PLAIN / DERIVED / VIRTUAL\n"
+            + "    --delete {SCHEMA-TYPE} {SCHEMA-KEY}\n"
+            + "        Schema type: PLAIN / DERIVED / VIRTUAL";
 
     @Override
+
     public void execute(final Input input) {
         LOG.debug("Option: {}", input.getOption());
         LOG.debug("Parameters:");
@@ -101,7 +103,7 @@ public class SchemaCommand extends AbstractCommand {
                         Messages.printMessage(ex.getMessage());
                     } catch (final IllegalArgumentException ex) {
                         Messages.printTypeNotValidMessage(
-                                "schema", input.firstParameter(), fromEnumToArray(SchemaType.class));
+                                "schema", input.firstParameter(), CommandUtils.fromEnumToArray(SchemaType.class));
                     }
                 } else {
                     Messages.printCommandOptionMessage(listErrorMessage);
@@ -216,7 +218,7 @@ public class SchemaCommand extends AbstractCommand {
                         }
                     } catch (final IllegalArgumentException ex) {
                         Messages.printTypeNotValidMessage(
-                                "schema", input.firstParameter(), fromEnumToArray(SchemaType.class));
+                                "schema", input.firstParameter(), CommandUtils.fromEnumToArray(SchemaType.class));
                     }
                 } else {
                     Messages.printCommandOptionMessage(readErrorMessage);
@@ -243,7 +245,7 @@ public class SchemaCommand extends AbstractCommand {
                         }
                     } catch (final IllegalArgumentException ex) {
                         Messages.printTypeNotValidMessage(
-                                "schema", input.firstParameter(), fromEnumToArray(SchemaType.class));
+                                "schema", input.firstParameter(), CommandUtils.fromEnumToArray(SchemaType.class));
                     }
                 } else {
                     Messages.printCommandOptionMessage(deleteErrorMessage);

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
index 9dcb795..5828823 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/TaskCommand.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.client.cli.commands;
 
+import org.apache.syncope.client.cli.commands.logger.LoggerCommand;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -27,6 +28,7 @@ import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.util.CommandUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AbstractTaskTO;
 import org.apache.syncope.common.lib.to.AnyTO;
@@ -230,7 +232,8 @@ public class TaskCommand extends AbstractCommand {
                     } catch (final SyncopeClientException ex) {
                         Messages.printMessage(ex.getMessage());
                     } catch (final IllegalArgumentException ex) {
-                        Messages.printTypeNotValidMessage("task", parameters[0], fromEnumToArray(TaskType.class));
+                        Messages.printTypeNotValidMessage(
+                                "task", parameters[0], CommandUtils.fromEnumToArray(TaskType.class));
                     }
                 } else {
                     Messages.printCommandOptionMessage(listTaskErrorMessage);
@@ -493,7 +496,6 @@ public class TaskCommand extends AbstractCommand {
                         final TaskExecTO taskExecTO = taskService.execute(taskIdToExecute, dryRun);
                         printTaskExecTO(taskExecTO);
                     } catch (final WebServiceException | SyncopeClientException ex) {
-                        System.out.println("Error:");
                         if (ex.getMessage().startsWith("NotFound")) {
                             Messages.printNofFoundMessage("Task", parameters[0]);
                         } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
index e049a28..0092210 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/install/InstallCommand.java
@@ -29,7 +29,7 @@ import org.apache.syncope.client.cli.Command;
 import org.apache.syncope.client.cli.Input;
 import org.apache.syncope.client.cli.SyncopeServices;
 import org.apache.syncope.client.cli.commands.AbstractCommand;
-import org.apache.syncope.client.cli.commands.LoggerCommand;
+import org.apache.syncope.client.cli.commands.logger.LoggerCommand;
 import org.apache.syncope.client.cli.util.FileSystemUtils;
 import org.apache.syncope.client.cli.util.JasyptUtils;
 import org.apache.syncope.common.rest.api.service.SyncopeService;

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
new file mode 100644
index 0000000..4654cb6
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/AbstractLoggerCommand.java
@@ -0,0 +1,30 @@
+/*
+ * 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.cli.commands.logger;
+
+import org.apache.syncope.client.cli.SyncopeServices;
+import org.apache.syncope.common.rest.api.service.LoggerService;
+
+public class AbstractLoggerCommand {
+
+    protected final LoggerService loggerService = SyncopeServices.get(LoggerService.class);
+    
+    protected final ResultManager resultManager = new ResultManager();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
new file mode 100644
index 0000000..1199218
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCommand.java
@@ -0,0 +1,128 @@
+/*
+ * 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.cli.commands.logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.commands.AbstractCommand;
+import org.apache.syncope.client.cli.messages.Messages;
+
+@Command(name = "logger")
+public class LoggerCommand extends AbstractCommand {
+
+    private static final String HELP_MESSAGE = "Usage: logger [options]\n"
+            + "  Options:\n"
+            + "    --help \n"
+            + "    --list \n"
+            + "    --read \n"
+            + "       Syntax: --read {LOG-NAME} {LOG-NAME} [...]\n"
+            + "    --update \n"
+            + "       Syntax: --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]\n"
+            + "    --update-all \n"
+            + "       Syntax: --update-all {LOG-LEVEL} \n"
+            + "    --create \n"
+            + "       Syntax: --create {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]\n"
+            + "    --delete \n"
+            + "       Syntax: --delete {LOG-NAME} {LOG-NAME} [...]";
+
+    @Override
+    public void execute(final Input input) {
+        if (StringUtils.isBlank(input.getOption())) {
+            input.setOption(LoggerOptions.HELP.getOptionName());
+        }
+
+        switch (LoggerOptions.fromName(input.getOption())) {
+            case LIST:
+                new LoggerList().list();
+                break;
+            case READ:
+                new LoggerRead(input).read();
+                break;
+            case UPDATE:
+                new LoggerUpdate(input).update();
+                break;
+            case UPDATE_ALL:
+                new LoggerUpdateAll(input).updateAll();
+                break;
+            case CREATE:
+                new LoggerCreate(input).create();
+                break;
+            case DELETE:
+                new LoggerDelete(input).delete();
+                break;
+            case HELP:
+                System.out.println(HELP_MESSAGE);
+                break;
+            default:
+                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
+        }
+    }
+
+    @Override
+    public String getHelpMessage() {
+        return HELP_MESSAGE;
+    }
+
+    private enum LoggerOptions {
+
+        HELP("--help"),
+        LIST("--list"),
+        READ("--read"),
+        UPDATE("--update"),
+        UPDATE_ALL("--update-all"),
+        CREATE("--create"),
+        DELETE("--delete");
+
+        private final String optionName;
+
+        private LoggerOptions(final String optionName) {
+            this.optionName = optionName;
+        }
+
+        public String getOptionName() {
+            return optionName;
+        }
+
+        public boolean equalsOptionName(final String otherName) {
+            return (otherName == null) ? false : optionName.equals(otherName);
+        }
+
+        public static LoggerOptions fromName(final String name) {
+            LoggerOptions optionToReturn = HELP;
+            for (final LoggerOptions option : LoggerOptions.values()) {
+                if (option.equalsOptionName(name)) {
+                    optionToReturn = option;
+                }
+            }
+            return optionToReturn;
+        }
+
+        public static List<String> toList() {
+            final List<String> options = new ArrayList<>();
+            for (final LoggerOptions value : values()) {
+                options.add(value.getOptionName());
+            }
+            return options;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
new file mode 100644
index 0000000..1444938
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerCreate.java
@@ -0,0 +1,71 @@
+/*
+ * 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.cli.commands.logger;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.util.CommandUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.LoggerTO;
+import org.apache.syncope.common.lib.types.LoggerLevel;
+import org.apache.syncope.common.lib.types.LoggerType;
+
+public class LoggerCreate extends AbstractLoggerCommand {
+
+    private static final String CREATE_HELP_MESSAGE
+            = "logger --create {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
+
+    private final Input input;
+
+    public LoggerCreate(final Input input) {
+        this.input = input;
+    }
+
+    public void create() {
+        if (input.parameterNumber() >= 1) {
+            Input.PairParameter pairParameter;
+            LoggerTO loggerTO;
+            final LinkedList<LoggerTO> loggerTOs = new LinkedList<>();
+            boolean failed = false;
+            for (final String parameter : input.getParameters()) {
+                loggerTO = new LoggerTO();
+                try {
+                    pairParameter = input.toPairParameter(parameter);
+                    loggerTO.setKey(pairParameter.getKey());
+                    loggerTO.setLevel(LoggerLevel.valueOf(pairParameter.getValue()));
+                    loggerService.update(LoggerType.LOG, loggerTO);
+                    loggerTOs.add(loggerTO);
+                } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
+                    Messages.printTypeNotValidMessage(
+                            "logger level", input.firstParameter(), CommandUtils.fromEnumToArray(LoggerLevel.class));
+                    failed = true;
+                    break;
+                }
+            }
+            if (!failed) {
+                resultManager.fromUpdate(loggerTOs);
+            }
+        } else {
+            Messages.printCommandOptionMessage(CREATE_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
new file mode 100644
index 0000000..49becd5
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerDelete.java
@@ -0,0 +1,63 @@
+/*
+ * 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.cli.commands.logger;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.LoggerTO;
+import org.apache.syncope.common.lib.types.LoggerType;
+
+public class LoggerDelete extends AbstractLoggerCommand {
+
+    private static final String DELETE_HELP_MESSAGE = "logger --delete {LOG-NAME} {LOG-NAME} [...]";
+
+    private final Input input;
+
+    public LoggerDelete(final Input input) {
+        this.input = input;
+    }
+
+    public void delete() {
+        if (input.parameterNumber() >= 1) {
+            final LinkedList<LoggerTO> loggerTOs = new LinkedList<>();
+            boolean failed = false;
+            for (final String parameter : input.getParameters()) {
+                try {
+                    loggerService.delete(LoggerType.LOG, parameter);
+                } catch (final WebServiceException | SyncopeClientException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        Messages.printNofFoundMessage("Logger", parameter);
+                    } else {
+                        Messages.printMessage(ex.getMessage());
+                    }
+                    failed = true;
+                }
+            }
+            if (!failed) {
+                resultManager.fromDelete(loggerTOs);
+            }
+        } else {
+            Messages.printCommandOptionMessage(DELETE_HELP_MESSAGE);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
new file mode 100644
index 0000000..78d2ced
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerList.java
@@ -0,0 +1,38 @@
+/*
+ * 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.cli.commands.logger;
+
+import java.util.LinkedList;
+import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.types.LoggerType;
+
+public class LoggerList extends AbstractLoggerCommand {
+
+    public LoggerList() {
+    }
+
+    public void list() {
+        try {
+            resultManager.fromList(new LinkedList<>(loggerService.list(LoggerType.LOG)));
+        } catch (final SyncopeClientException ex) {
+            Messages.printMessage("Error: " + ex.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
new file mode 100644
index 0000000..4d33191
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerRead.java
@@ -0,0 +1,63 @@
+/*
+ * 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.cli.commands.logger;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.LoggerTO;
+import org.apache.syncope.common.lib.types.LoggerType;
+
+public class LoggerRead extends AbstractLoggerCommand {
+
+    private static final String READ_HELP_MESSAGE = "logger --read {LOG-NAME} {LOG-NAME} [...]";
+
+    private final Input input;
+
+    public LoggerRead(final Input input) {
+        this.input = input;
+    }
+
+    public void read() {
+        if (input.getParameters().length >= 1) {
+            final LinkedList<LoggerTO> loggerTOs = new LinkedList<>();
+            boolean failed = false;
+            for (final String parameter : input.getParameters()) {
+                try {
+                    loggerTOs.add(loggerService.read(LoggerType.LOG, parameter));
+                } catch (final SyncopeClientException | WebServiceException ex) {
+                    if (ex.getMessage().startsWith("NotFound")) {
+                        Messages.printNofFoundMessage("Logger", parameter);
+                    } else {
+                        Messages.printMessage("Error: " + ex.getMessage());
+                    }
+                    failed = true;
+                    break;
+                }
+            }
+            if (!failed) {
+                resultManager.fromRead(loggerTOs);
+            }
+        } else {
+            Messages.printCommandOptionMessage(READ_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
new file mode 100644
index 0000000..fccfe72
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdate.java
@@ -0,0 +1,78 @@
+/*
+ * 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.cli.commands.logger;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.util.CommandUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.LoggerTO;
+import org.apache.syncope.common.lib.types.LoggerLevel;
+import org.apache.syncope.common.lib.types.LoggerType;
+
+public class LoggerUpdate extends AbstractLoggerCommand {
+
+    private static final String UPDATE_HELP_MESSAGE
+            = "logger --update {LOG-NAME}={LOG-LEVEL} {LOG-NAME}={LOG-LEVEL} [...]";
+
+    private final Input input;
+
+    public LoggerUpdate(final Input input) {
+        this.input = input;
+    }
+
+    public void update() {
+        if (input.parameterNumber() >= 1) {
+            Input.PairParameter pairParameter;
+            LoggerTO loggerTO;
+            final LinkedList<LoggerTO> loggerTOs = new LinkedList<>();
+            boolean failed = false;
+            for (final String parameter : input.getParameters()) {
+                try {
+                    pairParameter = input.toPairParameter(parameter);
+                    loggerTO = loggerService.read(LoggerType.LOG, pairParameter.getKey());
+                    loggerTO.setLevel(LoggerLevel.valueOf(pairParameter.getValue()));
+                    loggerService.update(LoggerType.LOG, loggerTO);
+                    loggerTOs.add(loggerTO);
+                } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
+                    if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
+                        Messages.printTypeNotValidMessage(
+                                "logger level",
+                                input.firstParameter(), CommandUtils.fromEnumToArray(LoggerLevel.class));
+                    } else if ("Parameter syntax error!".equalsIgnoreCase(ex.getMessage())) {
+                        Messages.printMessage(ex.getMessage(), UPDATE_HELP_MESSAGE);
+                    } else if (ex.getMessage().startsWith("NotFound")) {
+                        Messages.printNofFoundMessage("Logger", parameter);
+                    } else {
+                        Messages.printMessage(ex.getMessage(), UPDATE_HELP_MESSAGE);
+                    }
+                    failed = true;
+                    break;
+                }
+            }
+            if (!failed) {
+                resultManager.fromUpdate(loggerTOs);
+            }
+        } else {
+            Messages.printCommandOptionMessage(UPDATE_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
new file mode 100644
index 0000000..b0ee25c
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/LoggerUpdateAll.java
@@ -0,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.cli.commands.logger;
+
+import java.util.LinkedList;
+import javax.xml.ws.WebServiceException;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.messages.Messages;
+import org.apache.syncope.client.cli.util.CommandUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.LoggerTO;
+import org.apache.syncope.common.lib.types.LoggerLevel;
+import org.apache.syncope.common.lib.types.LoggerType;
+
+public class LoggerUpdateAll extends AbstractLoggerCommand {
+
+    private static final String UPDATE_ALL_HELP_MESSAGE = "logger --update-all {LOG-LEVEL}";
+
+    private final Input input;
+
+    public LoggerUpdateAll(final Input input) {
+        this.input = input;
+    }
+
+    public void updateAll() {
+        if (input.parameterNumber() == 1) {
+            final LinkedList<LoggerTO> loggerTOs = new LinkedList<>();
+            boolean failed = false;
+            for (final LoggerTO loggerTO : loggerService.list(LoggerType.LOG)) {
+                try {
+                    loggerTO.setLevel(LoggerLevel.valueOf(input.firstParameter()));
+                    loggerService.update(LoggerType.LOG, loggerTO);
+                    loggerTOs.add(loggerTO);
+                } catch (final WebServiceException | SyncopeClientException | IllegalArgumentException ex) {
+                    if (ex.getMessage().startsWith("No enum constant org.apache.syncope.common.lib.types.")) {
+                        Messages.printTypeNotValidMessage(
+                                "logger level",
+                                input.firstParameter(), CommandUtils.fromEnumToArray(LoggerLevel.class));
+                    } else {
+                        Messages.printMessage(ex.getMessage(), UPDATE_ALL_HELP_MESSAGE);
+                    }
+                    failed = true;
+                    break;
+                }
+            }
+            if (!failed) {
+                resultManager.fromUpdate(loggerTOs);
+            }
+        } else {
+            Messages.printCommandOptionMessage(UPDATE_ALL_HELP_MESSAGE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java
new file mode 100644
index 0000000..102ff74
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/logger/ResultManager.java
@@ -0,0 +1,60 @@
+/*
+ * 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.cli.commands.logger;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import org.apache.syncope.client.cli.messages.Table;
+import org.apache.syncope.common.lib.to.LoggerTO;
+
+public class ResultManager {
+
+    public void fromList(final LinkedList<LoggerTO> loggerTOs) {
+        fromCommandToView("list loggers", "level", loggerTOs);
+    }
+
+    public void fromRead(final LinkedList<LoggerTO> loggerTOs) {
+        fromCommandToView("read loggers", "level", loggerTOs);
+    }
+
+    public void fromCreate(final LinkedList<LoggerTO> loggerTOs) {
+        fromCommandToView("created loggers", "level", loggerTOs);
+    }
+
+    public void fromUpdate(final LinkedList<LoggerTO> loggerTOs) {
+        fromCommandToView("updated loggers", "new level", loggerTOs);
+    }
+
+    public void fromDelete(final LinkedList<LoggerTO> loggerTOs) {
+        fromCommandToView("deleted loggers", "new level", loggerTOs);
+    }
+
+    private void fromCommandToView(final String title,
+            final String secondHeader,
+            final LinkedList<LoggerTO> loggerTOs) {
+        final Table.TableBuilder tableBuilder
+                = new Table.TableBuilder(title).header("logger").header(secondHeader);
+        for (final LoggerTO loggerTO : loggerTOs) {
+            tableBuilder.rowValues(
+                    new LinkedList(Arrays.asList(loggerTO.getKey(), loggerTO.getLevel().getLevel().name())));
+        }
+        tableBuilder.build().print();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Messages.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Messages.java b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Messages.java
index e2cb159..35550fd 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Messages.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Messages.java
@@ -22,6 +22,10 @@ public final class Messages {
 
     private static final String OPTION_COMMAND_MESSAGE_TEMPLATE = "\n - Usage: %s\n";
 
+    private static final String CREATED_MESSAGE_TEMPLATE = "%s %s successfully created";
+
+    private static final String UPDATED_MESSAGE_TEMPLATE = "%s %s successfully updated";
+
     private static final String DELETED_MESSAGE_TEMPLATE = "%s %s successfully deleted";
 
     private static final String DOESNT_EXIST_MESSAGE_TEMPLATE = "%s %s doesn't exist";
@@ -52,6 +56,14 @@ public final class Messages {
         printMessage(String.format(DOESNT_EXIST_MESSAGE_TEMPLATE, what, key));
     }
 
+    public static void printCreatedMessage(final String what, final String key) {
+        printMessage(String.format(CREATED_MESSAGE_TEMPLATE, what, key));
+    }
+
+    public static void printUpdatedMessage(final String what, final String key) {
+        printMessage(String.format(UPDATED_MESSAGE_TEMPLATE, what, key));
+    }
+
     public static void printDeletedMessage(final String what, final String key) {
         printMessage(String.format(DELETED_MESSAGE_TEMPLATE, what, key));
     }
@@ -59,7 +71,7 @@ public final class Messages {
     public static void printIdNotNumberDeletedMessage(final String what, final String key) {
         printMessage(String.format(ID_NOT_NUMBER_MESSAGE_TEMPLATE, key, what));
     }
-    
+
     public static void printNotBooleanDeletedMessage(final String what, final String key) {
         printMessage(String.format(NOT_BOOLEAN_MESSAGE_TEMPLATE, key, what));
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/47392366/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
new file mode 100644
index 0000000..4f22980
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/messages/Table.java
@@ -0,0 +1,190 @@
+/*
+ * 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.cli.messages;
+
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+
+public final class Table {
+
+    private static final String TABLE_TITLE_FORMAT = "#  %s  #\n";
+
+    private final String title;
+
+    private final LinkedList<String> headers;
+
+    private final Set<LinkedList<String>> values;
+
+    private int columnsNumber;
+
+    private String[] tmpValuesArray;
+
+    private String tableContentFormat;
+
+    private int[] columnsSize;
+
+    private int tableWidth;
+
+    private String border = "";
+
+    private Table(
+            final String title,
+            final LinkedList<String> headers,
+            final Set<LinkedList<String>> values) {
+        this.title = title;
+        this.headers = headers;
+        this.values = values;
+    }
+
+    public void print() {
+        columnsNumber = headers.size();
+        tmpValuesArray = new String[columnsNumber];
+
+        buildTableContentFormat();
+        initializeColumnSize();
+        countTableWidth();
+
+        printBorder();
+        printTitle();
+        printBorder();
+        printHeaders();
+        printBorder();
+        printeContent();
+        printBorder();
+    }
+
+    private void buildTableContentFormat() {
+        final StringBuilder tableContentFormatBuilder = new StringBuilder("#");
+        for (int s = 0; s < columnsNumber; s++) {
+            tableContentFormatBuilder.append("  %s  #");
+        }
+        tableContentFormatBuilder.append("\n");
+        tableContentFormat = tableContentFormatBuilder.toString();
+    }
+
+    private void initializeColumnSize() {
+        columnsSize = new int[columnsNumber];
+        for (int j = 0; j < columnsSize.length; j++) {
+            columnsSize[j] = 0;
+        }
+
+        for (int i = 0; i < columnsSize.length; i++) {
+            if (headers.get(i).length() > columnsSize[i]) {
+                columnsSize[i] = headers.get(i).length();
+            }
+        }
+
+        for (final LinkedList<String> value : values) {
+            for (int j = 0; j < columnsSize.length; j++) {
+                if (value.get(j).length() > columnsSize[j]) {
+                    columnsSize[j] = value.get(j).length();
+                }
+            }
+        }
+    }
+
+    private void countTableWidth() {
+        int maxColumnValueSum = 0;
+        for (int j = 0; j < columnsSize.length; j++) {
+            maxColumnValueSum = maxColumnValueSum + columnsSize[j];
+        }
+
+        tableWidth = maxColumnValueSum + (columnsNumber * (2 + 2)) + columnsNumber + 1;
+    }
+
+    private void printBorder() {
+        if (border.isEmpty()) {
+            final StringBuilder borderBuilder = new StringBuilder();
+            for (int j = 0; j < tableWidth; j++) {
+                borderBuilder.append("#");
+            }
+            border = borderBuilder.toString();
+        }
+
+        System.out.println(border);
+    }
+
+    private void printTitle() {
+        System.out.format(TABLE_TITLE_FORMAT, StringUtils.center(" ", tableWidth - 6));
+        System.out.format(TABLE_TITLE_FORMAT, StringUtils.center(title.toUpperCase(), tableWidth - 6));
+        System.out.format(TABLE_TITLE_FORMAT, StringUtils.center(" ", tableWidth - 6));
+    }
+
+    public void printHeaders() {
+        printColumnSpace();
+
+        for (int h = 0; h < columnsNumber; h++) {
+            tmpValuesArray[h] = StringUtils.center(headers.get(h).toUpperCase(), columnsSize[h]);
+        }
+
+        System.out.format(tableContentFormat, tmpValuesArray);
+
+        printColumnSpace();
+    }
+
+    private void printeContent() {
+        printColumnSpace();
+
+        for (LinkedList<String> value : values) {
+            for (int j = 0; j < columnsNumber; j++) {
+                tmpValuesArray[j] = StringUtils.center(value.get(j), columnsSize[j]);
+            }
+            System.out.format(tableContentFormat, tmpValuesArray);
+        }
+
+        printColumnSpace();
+    }
+
+    private void printColumnSpace() {
+        for (int h = 0; h < columnsNumber; h++) {
+            tmpValuesArray[h] = StringUtils.center(" ", columnsSize[h]);
+        }
+
+        System.out.format(tableContentFormat, tmpValuesArray);
+    }
+    
+    public static class TableBuilder {
+
+        private final LinkedList<String> headers = new LinkedList<>();
+
+        private final Set<LinkedList<String>> values = new LinkedHashSet<>();
+
+        private final String title;
+
+        public TableBuilder(final String title) {
+            this.title = title;
+        }
+
+        public TableBuilder header(final String header) {
+            headers.add(header);
+            return this;
+        }
+
+        public TableBuilder rowValues(final LinkedList<String> row) {
+            values.add(row);
+            return this;
+        }
+
+        public Table build() {
+            return new Table(title, headers, values);
+        }
+    }
+}


[32/54] [abbrv] syncope git commit: Fixed SYNCOPE-713

Posted by fm...@apache.org.
Fixed SYNCOPE-713


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

Branch: refs/heads/SYNCOPE-156
Commit: 3f58b93c195d2d80f010b3362aa8d445cfff6970
Parents: 6b9cd59
Author: massi <ma...@tirasa.net>
Authored: Wed Oct 21 12:13:45 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Wed Oct 21 12:13:45 2015 +0200

----------------------------------------------------------------------
 .../configuration/ConfigurationGet.java         |  2 +-
 .../console/rest/ConfigurationRestClient.java   | 15 ++++------
 .../apache/syncope/common/lib/to/ConfTO.java    | 30 --------------------
 .../rest/api/service/ConfigurationService.java  |  4 +--
 .../syncope/core/logic/ConfigurationLogic.java  |  8 +++---
 .../api/data/ConfigurationDataBinder.java       |  4 +--
 .../java/data/ConfigurationDataBinderImpl.java  | 21 +++++++-------
 .../cxf/service/ConfigurationServiceImpl.java   |  4 +--
 .../fit/core/reference/ConfigurationITCase.java |  6 ++--
 9 files changed, 31 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/3f58b93c/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
index 91f3dce..472e40f 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/configuration/ConfigurationGet.java
@@ -27,7 +27,7 @@ public class ConfigurationGet extends AbstractConfigurationCommand {
 
     public void get() {
         try {
-            configurationResultManager.fromGet(new LinkedList<>(configurationService.list().getPlainAttrs()));
+            configurationResultManager.fromGet(new LinkedList<>(configurationService.list()));
         } catch (final Exception ex) {
             configurationResultManager.genericError(ex.getMessage());
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/3f58b93c/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
index ade9408..c24cf53 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
@@ -18,14 +18,12 @@
  */
 package org.apache.syncope.client.console.rest;
 
-import java.util.Iterator;
 import java.util.List;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.commons.AttrLayoutType;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.to.ConfTO;
 import org.apache.syncope.common.rest.api.service.ConfigurationService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -38,19 +36,18 @@ public class ConfigurationRestClient extends BaseRestClient {
     @Autowired
     private SchemaRestClient schemaRestClient;
 
-    public ConfTO list() {
-        ConfTO conf = getService(ConfigurationService.class).list();
+    public List<AttrTO> list() {
+        final List<AttrTO> attrTOs = getService(ConfigurationService.class).list();
 
-        for (Iterator<AttrTO> it = conf.getPlainAttrs().iterator(); it.hasNext();) {
-            AttrTO attr = it.next();
+        for (AttrTO attrTO : attrTOs) {
             for (AttrLayoutType type : AttrLayoutType.values()) {
-                if (type.getConfKey().equals(attr.getSchema())) {
-                    it.remove();
+                if (type.getConfKey().equals(attrTO.getSchema())) {
+                    attrTOs.remove(attrTO);
                 }
             }
         }
 
-        return conf;
+        return attrTOs;
     }
 
     public AttrTO get(final String key) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/3f58b93c/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConfTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConfTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConfTO.java
deleted file mode 100644
index 77e1af2..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConfTO.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.common.lib.to;
-
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-@XmlRootElement(name = "conf")
-@XmlType
-public class ConfTO extends AnyTO {
-
-    private static final long serialVersionUID = -3825039700228595590L;
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/3f58b93c/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ConfigurationService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ConfigurationService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ConfigurationService.java
index 875ebc5..59339c4 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ConfigurationService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ConfigurationService.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.common.rest.api.service;
 
+import java.util.List;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -29,7 +30,6 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.to.ConfTO;
 
 /**
  * REST operations for configuration.
@@ -53,7 +53,7 @@ public interface ConfigurationService extends JAXRSService {
      */
     @GET
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    ConfTO list();
+    List<AttrTO> list();
 
     /**
      * Returns configuration parameter with matching schema.

http://git-wip-us.apache.org/repos/asf/syncope/blob/3f58b93c/core/logic/src/main/java/org/apache/syncope/core/logic/ConfigurationLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ConfigurationLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ConfigurationLogic.java
index b989ac2..3f0115d 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ConfigurationLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ConfigurationLogic.java
@@ -20,8 +20,8 @@ package org.apache.syncope.core.logic;
 
 import java.io.OutputStream;
 import java.lang.reflect.Method;
+import java.util.List;
 import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.to.ConfTO;
 import org.apache.syncope.common.lib.types.Entitlement;
 import org.apache.syncope.core.misc.security.AuthContextUtils;
 import org.apache.syncope.core.persistence.api.content.ContentExporter;
@@ -39,7 +39,7 @@ import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
 @Component
-public class ConfigurationLogic extends AbstractTransactionalLogic<ConfTO> {
+public class ConfigurationLogic extends AbstractTransactionalLogic<AttrTO> {
 
     @Autowired
     private ConfDAO confDAO;
@@ -73,7 +73,7 @@ public class ConfigurationLogic extends AbstractTransactionalLogic<ConfTO> {
     }
 
     @PreAuthorize("hasRole('" + Entitlement.CONFIGURATION_LIST + "')")
-    public ConfTO list() {
+    public List<AttrTO> list() {
         return binder.getConfTO(confDAO.get());
     }
 
@@ -114,7 +114,7 @@ public class ConfigurationLogic extends AbstractTransactionalLogic<ConfTO> {
     }
 
     @Override
-    protected ConfTO resolveReference(final Method method, final Object... args)
+    protected AttrTO resolveReference(final Method method, final Object... args)
             throws UnresolvedReferenceException {
 
         throw new UnresolvedReferenceException();

http://git-wip-us.apache.org/repos/asf/syncope/blob/3f58b93c/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ConfigurationDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ConfigurationDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ConfigurationDataBinder.java
index e3a27bc..020a6ae 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ConfigurationDataBinder.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ConfigurationDataBinder.java
@@ -18,8 +18,8 @@
  */
 package org.apache.syncope.core.provisioning.api.data;
 
+import java.util.List;
 import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.to.ConfTO;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.conf.Conf;
 
@@ -27,7 +27,7 @@ public interface ConfigurationDataBinder {
 
     AttrTO getAttrTO(CPlainAttr attr);
 
-    ConfTO getConfTO(Conf conf);
+    List<AttrTO> getConfTO(Conf conf);
 
     CPlainAttr getAttribute(AttrTO attributeTO);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/3f58b93c/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
index fe135b2..c0f0485 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
@@ -18,12 +18,12 @@
  */
 package org.apache.syncope.core.provisioning.java.data;
 
+import java.util.ArrayList;
 import org.apache.syncope.core.provisioning.api.data.ConfigurationDataBinder;
 import java.util.Collections;
 import java.util.List;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.to.ConfTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
@@ -34,21 +34,22 @@ import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.conf.Conf;
-import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.springframework.stereotype.Component;
 
 @Component
 public class ConfigurationDataBinderImpl extends AbstractAnyDataBinder implements ConfigurationDataBinder {
 
     @Override
-    public ConfTO getConfTO(final Conf conf) {
-        ConfTO confTO = new ConfTO();
-        confTO.setKey(conf.getKey());
-
-        fillTO(confTO, null, conf.getAuxClasses(),
-                conf.getPlainAttrs(), conf.getDerAttrs(), conf.getVirAttrs(), Collections.<ExternalResource>emptySet());
-
-        return confTO;
+    public List<AttrTO> getConfTO(final Conf conf) {
+        final List<AttrTO> attrTOs = new ArrayList<>();
+        for (final CPlainAttr plainAttr : conf.getPlainAttrs()) {
+            final AttrTO attrTO = new AttrTO();
+            attrTO.setSchema(plainAttr.getSchema().getKey());
+            attrTO.getValues().addAll(plainAttr.getValuesAsStrings());
+            attrTO.setReadonly(plainAttr.getSchema().isReadonly());
+            attrTOs.add(attrTO);
+        }
+        return attrTOs;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/3f58b93c/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ConfigurationServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ConfigurationServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ConfigurationServiceImpl.java
index 09e0779..1a6dac7 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ConfigurationServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ConfigurationServiceImpl.java
@@ -20,12 +20,12 @@ package org.apache.syncope.core.rest.cxf.service;
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.List;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.StreamingOutput;
 import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.to.ConfTO;
 import org.apache.syncope.common.rest.api.service.ConfigurationService;
 import org.apache.syncope.core.logic.ConfigurationLogic;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -60,7 +60,7 @@ public class ConfigurationServiceImpl extends AbstractServiceImpl implements Con
     }
 
     @Override
-    public ConfTO list() {
+    public List<AttrTO> list() {
         return logic.list();
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/3f58b93c/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ConfigurationITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ConfigurationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ConfigurationITCase.java
index 68761cd..6bc000e 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ConfigurationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/ConfigurationITCase.java
@@ -28,6 +28,7 @@ import static org.junit.Assert.fail;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
+import java.util.List;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -35,7 +36,6 @@ import org.apache.commons.io.IOUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.to.ConfTO;
 import org.apache.syncope.common.lib.to.PlainSchemaTO;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
@@ -89,9 +89,9 @@ public class ConfigurationITCase extends AbstractITCase {
 
     @Test
     public void list() {
-        ConfTO wholeConf = configurationService.list();
+        List<AttrTO> wholeConf = configurationService.list();
         assertNotNull(wholeConf);
-        for (AttrTO conf : wholeConf.getPlainAttrs()) {
+        for (AttrTO conf : wholeConf) {
             assertNotNull(conf);
         }
     }


[44/54] [abbrv] syncope git commit: [SYNCOPE-709] Refactoring completed

Posted by fm...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirAttr.java
deleted file mode 100644
index bb3ab70..0000000
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirAttr.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.persistence.api.entity.user;
-
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
-
-public interface UVirAttr extends VirAttr<User> {
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
index 884e849..0a51c48 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
@@ -26,7 +26,7 @@ import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.Role;
 
-public interface User extends Any<UPlainAttr, UDerAttr, UVirAttr> {
+public interface User extends Any<UPlainAttr, UDerAttr> {
 
     String getUsername();
 
@@ -116,18 +116,6 @@ public interface User extends Any<UPlainAttr, UDerAttr, UVirAttr> {
     @Override
     List<? extends UDerAttr> getDerAttrs();
 
-    @Override
-    boolean add(UVirAttr attr);
-
-    @Override
-    boolean remove(UVirAttr virAttr);
-
-    @Override
-    UVirAttr getVirAttr(String virSchemaName);
-
-    @Override
-    List<? extends UVirAttr> getVirAttrs();
-
     boolean add(Role role);
 
     boolean remove(Role role);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
index edd430e..125b447 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
@@ -27,7 +27,7 @@ import java.util.Map;
 import javax.sql.DataSource;
 import org.apache.commons.codec.DecoderException;
 import org.apache.commons.codec.binary.Hex;
-import org.apache.syncope.core.misc.DataFormat;
+import org.apache.syncope.core.misc.FormatUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.dao.DataAccessException;
@@ -125,7 +125,7 @@ class ContentLoaderHandler extends DefaultHandler {
                 case Types.TIME:
                 case Types.TIMESTAMP:
                     try {
-                        parameters[i] = DataFormat.parseDate(attrs.getValue(i));
+                        parameters[i] = FormatUtils.parseDate(attrs.getValue(i));
                     } catch (ParseException e) {
                         LOG.error("Unparsable Date '{}'", attrs.getValue(i));
                         parameters[i] = attrs.getValue(i);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
index 17f4bce..9512849 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
@@ -50,7 +50,7 @@ import javax.xml.transform.stream.StreamResult;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.core.misc.DataFormat;
+import org.apache.syncope.core.misc.FormatUtils;
 import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.content.ContentExporter;
 import org.apache.syncope.core.persistence.jpa.entity.JPAReportExec;
@@ -60,7 +60,6 @@ import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAPlainAttrValue;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAARelationship;
-import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAVirAttr;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAnyObject;
 import org.apache.syncope.core.persistence.jpa.entity.task.JPATaskExec;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUDerAttr;
@@ -69,7 +68,6 @@ import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAURelationship;
-import org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
 import org.springframework.jdbc.datasource.DataSourceUtils;
 import org.springframework.security.crypto.codec.Hex;
@@ -87,9 +85,9 @@ public class XMLContentExporter extends AbstractContentDealer implements Content
             new HashSet<>(Arrays.asList(new String[] {
                 "QRTZ_", "LOGGING", JPAReportExec.TABLE, JPATaskExec.TABLE,
                 JPAUser.TABLE, JPAUPlainAttr.TABLE, JPAUPlainAttrValue.TABLE, JPAUPlainAttrUniqueValue.TABLE,
-                JPAUDerAttr.TABLE, JPAUVirAttr.TABLE,
+                JPAUDerAttr.TABLE,
                 JPAAnyObject.TABLE, JPAAPlainAttr.TABLE, JPAAPlainAttrValue.TABLE, JPAAPlainAttrUniqueValue.TABLE,
-                JPAADerAttr.TABLE, JPAAVirAttr.TABLE,
+                JPAADerAttr.TABLE,
                 JPAARelationship.TABLE, JPAAMembership.TABLE, JPAURelationship.TABLE, JPAUMembership.TABLE
             }));
 
@@ -206,7 +204,7 @@ public class XMLContentExporter extends AbstractContentDealer implements Content
                 case Types.TIMESTAMP:
                     final Timestamp timestamp = rs.getTimestamp(columnName);
                     if (timestamp != null) {
-                        res = DataFormat.format(new Date(timestamp.getTime()));
+                        res = FormatUtils.format(new Date(timestamp.getTime()));
                     }
                     break;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
index 95f5b4e..960251f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
@@ -47,14 +47,13 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttrValue;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 
-public abstract class AbstractAnyDAO<A extends Any<?, ?, ?>> extends AbstractDAO<A, Long> implements AnyDAO<A> {
+public abstract class AbstractAnyDAO<A extends Any<?, ?>> extends AbstractDAO<A, Long> implements AnyDAO<A> {
 
     @Autowired
     protected PlainSchemaDAO plainSchemaDAO;
@@ -415,13 +414,7 @@ public abstract class AbstractAnyDAO<A extends Any<?, ?, ?>> extends AbstractDAO
 
     @Override
     public A save(final A any) {
-        A merged = entityManager().merge(any);
-        for (VirAttr<?> virAttr : merged.getVirAttrs()) {
-            virAttr.getValues().clear();
-            virAttr.getValues().addAll(any.getVirAttr(virAttr.getSchema().getKey()).getValues());
-        }
-
-        return merged;
+        return entityManager().merge(any);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
index 2b422eb..2acd683 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
@@ -67,7 +67,7 @@ import org.springframework.stereotype.Repository;
 import org.springframework.util.ReflectionUtils;
 
 @Repository
-public class JPAAnySearchDAO extends AbstractDAO<Any<?, ?, ?>, Long> implements AnySearchDAO {
+public class JPAAnySearchDAO extends AbstractDAO<Any<?, ?>, Long> implements AnySearchDAO {
 
     private static final String EMPTY_ATTR_QUERY = "SELECT any_id FROM user_search_attr WHERE 1=2";
 
@@ -150,14 +150,14 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?, ?, ?>, Long> implements
     }
 
     @Override
-    public <T extends Any<?, ?, ?>> List<T> search(
+    public <T extends Any<?, ?>> List<T> search(
             final Set<String> adminRealms, final SearchCond searchCondition, final AnyTypeKind typeKind) {
 
         return search(adminRealms, searchCondition, Collections.<OrderByClause>emptyList(), typeKind);
     }
 
     @Override
-    public <T extends Any<?, ?, ?>> List<T> search(
+    public <T extends Any<?, ?>> List<T> search(
             final Set<String> adminRealms, final SearchCond searchCondition, final List<OrderByClause> orderBy,
             final AnyTypeKind typeKind) {
 
@@ -165,7 +165,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?, ?, ?>, Long> implements
     }
 
     @Override
-    public <T extends Any<?, ?, ?>> List<T> search(
+    public <T extends Any<?, ?>> List<T> search(
             final Set<String> adminRealms, final SearchCond searchCondition, final int page, final int itemsPerPage,
             final List<OrderByClause> orderBy, final AnyTypeKind typeKind) {
 
@@ -189,7 +189,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?, ?, ?>, Long> implements
     }
 
     @Override
-    public <T extends Any<?, ?, ?>> boolean matches(
+    public <T extends Any<?, ?>> boolean matches(
             final T any, final SearchCond searchCondition, final AnyTypeKind typeKind) {
 
         List<Object> parameters = Collections.synchronizedList(new ArrayList<>());
@@ -347,7 +347,7 @@ public class JPAAnySearchDAO extends AbstractDAO<Any<?, ?, ?>, Long> implements
     }
 
     @SuppressWarnings("unchecked")
-    private <T extends Any<?, ?, ?>> List<T> doSearch(final Set<String> adminRealms,
+    private <T extends Any<?, ?>> List<T> doSearch(final Set<String> adminRealms,
             final SearchCond nodeCond, final int page, final int itemsPerPage, final List<OrderByClause> orderBy,
             final AnyTypeKind typeKind) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerAttrDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerAttrDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerAttrDAO.java
index 8dff203..99b9014 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerAttrDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerAttrDAO.java
@@ -78,7 +78,7 @@ public class JPADerAttrDAO extends AbstractDAO<DerAttr<?>, Long> implements DerA
     @SuppressWarnings("unchecked")
     public <T extends DerAttr<?>> void delete(final T derAttr) {
         if (derAttr.getOwner() != null) {
-            ((Any<?, T, ?>) derAttr.getOwner()).remove(derAttr);
+            ((Any<?, T>) derAttr.getOwner()).remove(derAttr);
         }
 
         entityManager().remove(derAttr);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
index 3905d92..0650ee9 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
@@ -32,10 +32,12 @@ import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.TaskDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.policy.AccountPolicy;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.Policy;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
@@ -43,6 +45,7 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAMappingItem;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResource;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAMapping;
+import org.apache.syncope.core.persistence.jpa.entity.resource.JPAProvision;
 import org.apache.syncope.core.provisioning.api.ConnectorRegistry;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
@@ -67,6 +70,9 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String
     private PolicyDAO policyDAO;
 
     @Autowired
+    private VirSchemaDAO virSchemaDAO;
+
+    @Autowired
     private ConnectorRegistry connRegistry;
 
     @Override
@@ -74,6 +80,11 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String
         return entityManager().find(JPAExternalResource.class, name);
     }
 
+    @Override
+    public Provision findProvision(final Long key) {
+        return entityManager().find(JPAProvision.class, key);
+    }
+
     private StringBuilder getByPolicyQuery(final PolicyType type) {
         StringBuilder query = new StringBuilder("SELECT e FROM ").
                 append(JPAExternalResource.class.getSimpleName()).
@@ -203,13 +214,6 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String
             policy.remove(resource);
         }
 
-        if (resource.getConnector() != null && resource.getConnector().getResources() != null
-                && !resource.getConnector().getResources().isEmpty()) {
-
-            resource.getConnector().getResources().remove(resource);
-        }
-        resource.setConnector(null);
-
         for (Provision provision : resource.getProvisions()) {
             for (MappingItem item : provision.getMapping().getItems()) {
                 item.setMapping(null);
@@ -217,7 +221,18 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String
             provision.getMapping().getItems().clear();
             provision.setMapping(null);
             provision.setResource(null);
+
+            for (VirSchema schema : virSchemaDAO.findByProvision(provision)) {
+                virSchemaDAO.delete(schema.getKey());
+            }
+        }
+
+        if (resource.getConnector() != null && resource.getConnector().getResources() != null
+                && !resource.getConnector().getResources().isEmpty()) {
+
+            resource.getConnector().getResources().remove(resource);
         }
+        resource.setConnector(null);
 
         entityManager().remove(resource);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index 652c1f7..4c29c90 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -203,7 +203,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
     }
 
     private void populateTransitiveResources(
-            final Group group, final Any<?, ?, ?> any, final Map<Long, PropagationByResource> result) {
+            final Group group, final Any<?, ?> any, final Map<Long, PropagationByResource> result) {
 
         PropagationByResource propByRes = new PropagationByResource();
         for (ExternalResource resource : group.getResources()) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
index d21d1f3..cec3d5b 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
@@ -68,7 +68,7 @@ public class JPAPlainAttrDAO extends AbstractDAO<PlainAttr<?>, Long> implements
     @SuppressWarnings("unchecked")
     public <T extends PlainAttr<?>> void delete(final T plainAttr) {
         if (plainAttr.getOwner() != null) {
-            ((Any<T, ?, ?>) plainAttr.getOwner()).remove(plainAttr);
+            ((Any<T, ?>) plainAttr.getOwner()).remove(plainAttr);
         }
 
         entityManager().remove(plainAttr);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrValueDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrValueDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrValueDAO.java
index 312d6fc..60f3786 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrValueDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrValueDAO.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.persistence.jpa.dao;
 import java.util.List;
 import javax.persistence.TypedQuery;
 import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrValue;
@@ -99,7 +100,11 @@ public class JPAPlainAttrValueDAO extends AbstractDAO<PlainAttrValue, Long> impl
     @Override
     public <T extends PlainAttrValue> void delete(final T attrValue) {
         if (attrValue.getAttr() != null) {
-            attrValue.getAttr().remove(attrValue);
+            if (attrValue instanceof PlainAttrUniqueValue) {
+                attrValue.getAttr().setUniqueValue(null);
+            } else {
+                attrValue.getAttr().remove(attrValue);
+            }
         }
 
         entityManager().remove(attrValue);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirAttrDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirAttrDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirAttrDAO.java
deleted file mode 100644
index 2c8b99f..0000000
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirAttrDAO.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.persistence.jpa.dao;
-
-import java.util.List;
-import javax.persistence.TypedQuery;
-import org.apache.syncope.core.persistence.api.dao.VirAttrDAO;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
-import org.apache.syncope.core.persistence.api.entity.anyobject.AVirAttr;
-import org.apache.syncope.core.persistence.api.entity.group.GVirAttr;
-import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractVirAttr;
-import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAVirAttr;
-import org.apache.syncope.core.persistence.jpa.entity.group.JPAGVirAttr;
-import org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr;
-import org.springframework.stereotype.Repository;
-
-@Repository
-public class JPAVirAttrDAO extends AbstractDAO<VirAttr<?>, Long> implements VirAttrDAO {
-
-    public <T extends VirAttr<?>> Class<? extends AbstractVirAttr<?>> getJPAEntityReference(
-            final Class<T> reference) {
-
-        return GVirAttr.class.isAssignableFrom(reference)
-                ? JPAGVirAttr.class
-                : AVirAttr.class.isAssignableFrom(reference)
-                        ? JPAAVirAttr.class
-                        : UVirAttr.class.isAssignableFrom(reference)
-                                ? JPAUVirAttr.class
-                                : null;
-    }
-
-    @Override
-    public <T extends VirAttr<?>> T find(final Long key, final Class<T> reference) {
-        return reference.cast(entityManager().find(getJPAEntityReference(reference), key));
-    }
-
-    @Override
-    public <T extends VirAttr<?>> List<T> findAll(final Class<T> reference) {
-        TypedQuery<T> query = entityManager().createQuery(
-                "SELECT e FROM " + getJPAEntityReference(reference).getSimpleName() + " e", reference);
-        return query.getResultList();
-    }
-
-    @Override
-    public <T extends VirAttr<?>> T save(final T virAttr) {
-        return entityManager().merge(virAttr);
-    }
-
-    @Override
-    public <T extends VirAttr<?>> void delete(final Long key, final Class<T> reference) {
-        T virAttr = find(key, reference);
-        if (virAttr == null) {
-            return;
-        }
-
-        delete(virAttr);
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public <T extends VirAttr<?>> void delete(final T virAttr) {
-        if (virAttr.getOwner() != null) {
-            ((Any<?, ?, T>) virAttr.getOwner()).remove(virAttr);
-        }
-
-        entityManager().remove(virAttr);
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
index 46a06f6..d4bce14 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
@@ -18,17 +18,18 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
+import java.util.Collections;
 import java.util.List;
 import javax.persistence.TypedQuery;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
-import org.apache.syncope.core.persistence.api.dao.VirAttrDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
+import org.apache.syncope.core.persistence.api.entity.Attr;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
 import org.apache.syncope.core.persistence.jpa.entity.JPAVirSchema;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -38,9 +39,6 @@ import org.springframework.stereotype.Repository;
 public class JPAVirSchemaDAO extends AbstractDAO<VirSchema, String> implements VirSchemaDAO {
 
     @Autowired
-    private VirAttrDAO virAttrDAO;
-
-    @Autowired
     private ExternalResourceDAO resourceDAO;
 
     @Override
@@ -61,6 +59,18 @@ public class JPAVirSchemaDAO extends AbstractDAO<VirSchema, String> implements V
     }
 
     @Override
+    public List<VirSchema> findByProvision(final Provision provision) {
+        StringBuilder queryString = new StringBuilder("SELECT e FROM ").
+                append(JPAVirSchema.class.getSimpleName()).
+                append(" e WHERE e.provision=:provision");
+
+        TypedQuery<VirSchema> query = entityManager().createQuery(queryString.toString(), VirSchema.class);
+        query.setParameter("provision", provision);
+
+        return query.getResultList();
+    }
+
+    @Override
     public List<VirSchema> findAll() {
         TypedQuery<VirSchema> query = entityManager().createQuery(
                 "SELECT e FROM " + JPAVirSchema.class.getSimpleName() + " e", VirSchema.class);
@@ -68,15 +78,8 @@ public class JPAVirSchemaDAO extends AbstractDAO<VirSchema, String> implements V
     }
 
     @Override
-    public <T extends VirAttr<?>> List<T> findAttrs(final VirSchema schema, final Class<T> reference) {
-        final StringBuilder queryString = new StringBuilder("SELECT e FROM ").
-                append(((JPAVirAttrDAO) virAttrDAO).getJPAEntityReference(reference).getSimpleName()).
-                append(" e WHERE e.schema=:schema");
-
-        TypedQuery<T> query = entityManager().createQuery(queryString.toString(), reference);
-        query.setParameter("schema", schema);
-
-        return query.getResultList();
+    public <T extends Attr<VirSchema, ?>> List<T> findAttrs(final VirSchema schema, final Class<T> reference) {
+        return Collections.emptyList();
     }
 
     @Override
@@ -95,10 +98,6 @@ public class JPAVirSchemaDAO extends AbstractDAO<VirSchema, String> implements V
         for (AnyTypeKind anyTypeKind : AnyTypeKind.values()) {
             AnyUtils anyUtils = anyUtilsFactory.getInstance(anyTypeKind);
 
-            for (VirAttr<?> attr : findAttrs(schema, anyUtils.virAttrClass())) {
-                virAttrDAO.delete(attr.getKey(), anyUtils.virAttrClass());
-            }
-
             resourceDAO.deleteMapping(key, anyUtils.virIntMappingType());
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
index 2e344b0..041c54f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
@@ -39,7 +39,6 @@ import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
@@ -49,9 +48,9 @@ import org.apache.syncope.core.persistence.api.entity.user.UMembership;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 
 @MappedSuperclass
-public abstract class AbstractAny<P extends PlainAttr<?>, D extends DerAttr<?>, V extends VirAttr<?>>
+public abstract class AbstractAny<P extends PlainAttr<?>, D extends DerAttr<?>>
         extends AbstractAnnotatedEntity<Long>
-        implements Any<P, D, V> {
+        implements Any<P, D> {
 
     private static final long serialVersionUID = -2666540708092702810L;
 
@@ -127,18 +126,6 @@ public abstract class AbstractAny<P extends PlainAttr<?>, D extends DerAttr<?>,
         });
     }
 
-    @Override
-    public V getVirAttr(final String virSchemaName) {
-        return CollectionUtils.find(getVirAttrs(), new Predicate<V>() {
-
-            @Override
-            public boolean evaluate(final V virAttr) {
-                return virAttr != null && virAttr.getSchema() != null
-                        && virSchemaName.equals(virAttr.getSchema().getKey());
-            }
-        });
-    }
-
     protected abstract List<JPAExternalResource> internalGetResources();
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttr.java
index ec37649..694b18f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttr.java
@@ -28,7 +28,7 @@ import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Schema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 
-public abstract class AbstractAttr<S extends Schema, O extends Any<?, ?, ?>>
+public abstract class AbstractAttr<S extends Schema, O extends Any<?, ?>>
         extends AbstractEntity<Long> implements Attr<S, O> {
 
     private static final long serialVersionUID = -7722134717360731874L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttr.java
index 4500a4e..59f390d 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttr.java
@@ -30,7 +30,7 @@ import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
 
 @MappedSuperclass
-public abstract class AbstractDerAttr<O extends Any<?, ?, ?>>
+public abstract class AbstractDerAttr<O extends Any<?, ?>>
         extends AbstractAttr<DerSchema, O> implements DerAttr<O> {
 
     private static final long serialVersionUID = 4740924251090424771L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDynMembership.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDynMembership.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDynMembership.java
index c5404e9..c7110d5 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDynMembership.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDynMembership.java
@@ -24,7 +24,7 @@ import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.DynMembership;
 
 @MappedSuperclass
-public abstract class AbstractDynMembership<A extends Any<?, ?, ?>>
+public abstract class AbstractDynMembership<A extends Any<?, ?>>
         extends AbstractEntity<Long> implements DynMembership<A> {
 
     private static final long serialVersionUID = 921821654690948787L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java
index 4bab427..fdd257e 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java
@@ -37,7 +37,7 @@ import org.apache.syncope.core.persistence.jpa.validation.entity.PlainAttrCheck;
 
 @MappedSuperclass
 @PlainAttrCheck
-public abstract class AbstractPlainAttr<O extends Any<?, ?, ?>>
+public abstract class AbstractPlainAttr<O extends Any<?, ?>>
         extends AbstractAttr<PlainSchema, O> implements PlainAttr<O> {
 
     private static final long serialVersionUID = -9115431608821806124L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
index 424e6a2..7032df6 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
@@ -32,11 +32,11 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.core.misc.FormatUtils;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
-import org.apache.syncope.core.misc.DataFormat;
 import org.apache.syncope.core.persistence.jpa.validation.entity.PlainAttrValueCheck;
 import org.apache.syncope.core.misc.security.Encryptor;
 
@@ -153,7 +153,7 @@ public abstract class AbstractPlainAttrValue extends AbstractEntity<Long> implem
                 try {
                     this.setLongValue(schema.getConversionPattern() == null
                             ? Long.valueOf(value)
-                            : DataFormat.parseNumber(value, schema.getConversionPattern()).longValue());
+                            : FormatUtils.parseNumber(value, schema.getConversionPattern()).longValue());
                 } catch (Exception pe) {
                     exception = pe;
                 }
@@ -163,7 +163,7 @@ public abstract class AbstractPlainAttrValue extends AbstractEntity<Long> implem
                 try {
                     this.setDoubleValue(schema.getConversionPattern() == null
                             ? Double.valueOf(value)
-                            : DataFormat.parseNumber(value, schema.getConversionPattern()).doubleValue());
+                            : FormatUtils.parseNumber(value, schema.getConversionPattern()).doubleValue());
                 } catch (Exception pe) {
                     exception = pe;
                 }
@@ -172,8 +172,8 @@ public abstract class AbstractPlainAttrValue extends AbstractEntity<Long> implem
             case Date:
                 try {
                     this.setDateValue(schema.getConversionPattern() == null
-                            ? DataFormat.parseDate(value)
-                            : new Date(DataFormat.parseDate(value, schema.getConversionPattern()).getTime()));
+                            ? FormatUtils.parseDate(value)
+                            : new Date(FormatUtils.parseDate(value, schema.getConversionPattern()).getTime()));
                 } catch (Exception pe) {
                     exception = pe;
                 }
@@ -246,21 +246,21 @@ public abstract class AbstractPlainAttrValue extends AbstractEntity<Long> implem
                 result = getAttr() == null || getAttr().getSchema() == null
                         || getAttr().getSchema().getConversionPattern() == null
                                 ? getLongValue().toString()
-                                : DataFormat.format(getLongValue(), getAttr().getSchema().getConversionPattern());
+                                : FormatUtils.format(getLongValue(), getAttr().getSchema().getConversionPattern());
                 break;
 
             case Double:
                 result = getAttr() == null || getAttr().getSchema() == null
                         || getAttr().getSchema().getConversionPattern() == null
                                 ? getDoubleValue().toString()
-                                : DataFormat.format(getDoubleValue(), getAttr().getSchema().getConversionPattern());
+                                : FormatUtils.format(getDoubleValue(), getAttr().getSchema().getConversionPattern());
                 break;
 
             case Date:
                 result = getAttr() == null || getAttr().getSchema() == null
                         || getAttr().getSchema().getConversionPattern() == null
-                                ? DataFormat.format(getDateValue())
-                                : DataFormat.format(getDateValue(), false, getAttr().getSchema().
+                                ? FormatUtils.format(getDateValue())
+                                : FormatUtils.format(getDateValue(), false, getAttr().getSchema().
                                         getConversionPattern());
                 break;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractVirAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractVirAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractVirAttr.java
deleted file mode 100644
index aebc8da..0000000
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractVirAttr.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.persistence.jpa.entity;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.persistence.Column;
-import javax.persistence.FetchType;
-import javax.persistence.ManyToOne;
-import javax.persistence.MappedSuperclass;
-import javax.persistence.Transient;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
-import org.apache.syncope.core.persistence.api.entity.VirSchema;
-
-@MappedSuperclass
-public abstract class AbstractVirAttr<O extends Any<?, ?, ?>>
-        extends AbstractAttr<VirSchema, O> implements VirAttr<O> {
-
-    private static final long serialVersionUID = 5023204776925954907L;
-
-    @Transient
-    protected List<String> values = new ArrayList<>();
-
-    @ManyToOne(fetch = FetchType.EAGER)
-    @Column(name = "schema_name")
-    private JPAVirSchema schema;
-
-    @Override
-    public List<String> getValues() {
-        return values;
-    }
-
-    @Override
-    public boolean add(final String value) {
-        return !values.contains(value) && values.add(value);
-    }
-
-    @Override
-    public boolean remove(final String value) {
-        return values.remove(value);
-    }
-
-    @Override
-    public VirSchema getSchema() {
-        return schema;
-    }
-
-    @Override
-    public void setSchema(final VirSchema schema) {
-        checkType(schema, JPAVirSchema.class);
-        this.schema = (JPAVirSchema) schema;
-        checkSchema(this.schema);
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AnnotatedEntityListener.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AnnotatedEntityListener.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AnnotatedEntityListener.java
index 4e8044d..c63a401 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AnnotatedEntityListener.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AnnotatedEntityListener.java
@@ -33,10 +33,10 @@ public class AnnotatedEntityListener {
     @PrePersist
     @PreUpdate
     public void setSysInfo(final AnnotatedEntity<?> entity) {
-        final String username = AuthContextUtils.getUsername();
+        String username = AuthContextUtils.getUsername();
         LOG.debug("Set system properties for '{}'", entity);
 
-        final Date now = new Date();
+        Date now = new Date();
 
         if (entity.getCreationDate() == null) {
             LOG.debug("Set creation date '{}' and creator '{}' for '{}'", now, username, entity);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
index 645c60c..7de2fbe 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
@@ -29,24 +29,20 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.DerAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADerAttr;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAPlainAttrValue;
-import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAVirAttr;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAnyObject;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGDerAttr;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGPlainAttrValue;
-import org.apache.syncope.core.persistence.jpa.entity.group.JPAGVirAttr;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUDerAttr;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue;
-import org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
 
 @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -64,7 +60,7 @@ public class JPAAnyUtils implements AnyUtils {
     }
 
     @Override
-    public <T extends Any<?, ?, ?>> Class<T> anyClass() {
+    public <T extends Any<?, ?>> Class<T> anyClass() {
         Class result;
 
         switch (anyTypeKind) {
@@ -266,52 +262,6 @@ public class JPAAnyUtils implements AnyUtils {
     }
 
     @Override
-    public <T extends VirAttr<?>> Class<T> virAttrClass() {
-        Class result = null;
-
-        switch (anyTypeKind) {
-            case USER:
-                result = JPAUVirAttr.class;
-                break;
-
-            case GROUP:
-                result = JPAGVirAttr.class;
-                break;
-
-            case ANY_OBJECT:
-                result = JPAAVirAttr.class;
-                break;
-
-            default:
-        }
-
-        return result;
-    }
-
-    @Override
-    public <T extends VirAttr<?>> T newVirAttr() {
-        T result = null;
-
-        switch (anyTypeKind) {
-            case USER:
-                result = (T) new JPAUVirAttr();
-                break;
-
-            case GROUP:
-                result = (T) new JPAGVirAttr();
-                break;
-
-            case ANY_OBJECT:
-                result = (T) new JPAAVirAttr();
-                break;
-
-            default:
-        }
-
-        return result;
-    }
-
-    @Override
     public IntMappingType plainIntMappingType() {
         IntMappingType result = null;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtilsFactory.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtilsFactory.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtilsFactory.java
index f68b3f9..38e08b4 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtilsFactory.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtilsFactory.java
@@ -41,7 +41,7 @@ public class JPAAnyUtilsFactory implements AnyUtilsFactory {
     }
 
     @Override
-    public AnyUtils getInstance(final Any<?, ?, ?> any) {
+    public AnyUtils getInstance(final Any<?, ?> any) {
         AnyTypeKind type = null;
         if (any instanceof User) {
             type = AnyTypeKind.USER;

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
index 4c3b816..372e062 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
@@ -64,7 +64,6 @@ import org.apache.syncope.core.persistence.api.entity.group.GDerAttr;
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.group.GVirAttr;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
@@ -85,7 +84,6 @@ import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.user.URelationship;
-import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADynGroupMembership;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAMembership;
@@ -102,7 +100,6 @@ import org.apache.syncope.core.persistence.jpa.entity.group.JPAGDerAttr;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGPlainAttrValue;
-import org.apache.syncope.core.persistence.jpa.entity.group.JPAGVirAttr;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAMapping;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAMappingItem;
@@ -122,7 +119,6 @@ import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAURelationship;
-import org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
 import org.springframework.stereotype.Component;
 
@@ -202,8 +198,6 @@ public class JPAEntityFactory implements EntityFactory {
             result = (T) new JPAUDerAttr();
         } else if (reference.equals(VirSchema.class)) {
             result = (T) new JPAVirSchema();
-        } else if (reference.equals(UVirAttr.class)) {
-            result = (T) new JPAUVirAttr();
         } else if (reference.equals(Mapping.class)) {
             result = (T) new JPAMapping();
         } else if (reference.equals(MappingItem.class)) {
@@ -216,8 +210,6 @@ public class JPAEntityFactory implements EntityFactory {
             result = (T) new JPAGPlainAttrUniqueValue();
         } else if (reference.equals(GDerAttr.class)) {
             result = (T) new JPAGDerAttr();
-        } else if (reference.equals(GVirAttr.class)) {
-            result = (T) new JPAGVirAttr();
         } else if (reference.equals(CPlainAttr.class)) {
             result = (T) new JPACPlainAttr();
         } else if (reference.equals(CPlainAttrValue.class)) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
index 6c1dd73..b984bb3 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAVirSchema.java
@@ -18,18 +18,28 @@
  */
 package org.apache.syncope.core.persistence.jpa.entity;
 
+import java.util.Collections;
+import java.util.List;
 import javax.persistence.Basic;
 import javax.persistence.Cacheable;
+import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.Id;
+import javax.persistence.ManyToOne;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.jpa.entity.resource.JPAProvision;
 import org.apache.syncope.core.persistence.jpa.validation.entity.SchemaNameCheck;
 
 @Entity
@@ -53,6 +63,13 @@ public class JPAVirSchema extends AbstractEntity<String> implements VirSchema {
     @Max(1)
     private Integer readonly;
 
+    @Column(nullable = false)
+    @ManyToOne
+    private JPAProvision provision;
+
+    @Column(nullable = false)
+    private String extAttrName;
+
     public JPAVirSchema() {
         super();
 
@@ -109,4 +126,134 @@ public class JPAVirSchema extends AbstractEntity<String> implements VirSchema {
     public void setReadonly(final boolean readonly) {
         this.readonly = getBooleanAsInteger(readonly);
     }
+
+    @Override
+    public Provision getProvision() {
+        return provision;
+    }
+
+    @Override
+    public void setProvision(final Provision provision) {
+        checkType(provision, JPAProvision.class);
+        this.provision = (JPAProvision) provision;
+    }
+
+    @Override
+    public String getExtAttrName() {
+        return extAttrName;
+    }
+
+    @Override
+    public void setExtAttrName(final String extAttrName) {
+        this.extAttrName = extAttrName;
+    }
+
+    @Override
+    public MappingItem asLinkingMappingItem() {
+        return new MappingItem() {
+
+            private static final long serialVersionUID = 327455459536715529L;
+
+            @Override
+            public Long getKey() {
+                return -1L;
+            }
+
+            @Override
+            public Mapping getMapping() {
+                return getProvision().getMapping();
+            }
+
+            @Override
+            public void setMapping(final Mapping mapping) {
+                // RO instance, nothing to do
+            }
+
+            @Override
+            public String getExtAttrName() {
+                return JPAVirSchema.this.getExtAttrName();
+            }
+
+            @Override
+            public void setExtAttrName(final String extAttrName) {
+                // RO instance, nothing to do
+            }
+
+            @Override
+            public String getIntAttrName() {
+                return JPAVirSchema.this.getKey();
+            }
+
+            @Override
+            public void setIntAttrName(final String intAttrName) {
+                // RO instance, nothing to do
+            }
+
+            @Override
+            public IntMappingType getIntMappingType() {
+                switch (getProvision().getAnyType().getKind()) {
+                    case ANY_OBJECT:
+                        return IntMappingType.AnyObjectVirtualSchema;
+
+                    case GROUP:
+                        return IntMappingType.GroupVirtualSchema;
+
+                    case USER:
+                    default:
+                        return IntMappingType.UserVirtualSchema;
+                }
+            }
+
+            @Override
+            public void setIntMappingType(final IntMappingType intMappingType) {
+                // RO instance, nothing to do
+            }
+
+            @Override
+            public String getMandatoryCondition() {
+                return JPAVirSchema.this.getMandatoryCondition();
+            }
+
+            @Override
+            public void setMandatoryCondition(final String condition) {
+                // RO instance, nothing to do
+            }
+
+            @Override
+            public MappingPurpose getPurpose() {
+                return JPAVirSchema.this.isReadonly() ? MappingPurpose.SYNCHRONIZATION : MappingPurpose.BOTH;
+            }
+
+            @Override
+            public void setPurpose(final MappingPurpose purpose) {
+                // RO instance, nothing to do
+            }
+
+            @Override
+            public boolean isConnObjectKey() {
+                return false;
+            }
+
+            @Override
+            public void setConnObjectKey(final boolean connObjectKey) {
+                // RO instance, nothing to do
+            }
+
+            @Override
+            public boolean isPassword() {
+                return false;
+            }
+
+            @Override
+            public void setPassword(final boolean password) {
+                // RO instance, nothing to do
+            }
+
+            @Override
+            public List<String> getMappingItemTransformerClassNames() {
+                return Collections.emptyList();
+            }
+        };
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttrUniqueValue.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttrUniqueValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttrUniqueValue.java
index 25cc5eb..01be6a8 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttrUniqueValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttrUniqueValue.java
@@ -60,7 +60,7 @@ public class JPAAPlainAttrUniqueValue extends AbstractPlainAttrValue implements
     }
 
     @Override
-    public void setAttr(final PlainAttr attr) {
+    public void setAttr(final PlainAttr<?> attr) {
         checkType(attr, JPAAPlainAttr.class);
         this.attribute = (JPAAPlainAttr) attr;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttrValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttrValue.java
index 73c962c..0c9e598 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttrValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttrValue.java
@@ -57,7 +57,7 @@ public class JPAAPlainAttrValue extends AbstractPlainAttrValue implements APlain
     }
 
     @Override
-    public void setAttr(final PlainAttr attr) {
+    public void setAttr(final PlainAttr<?> attr) {
         checkType(attr, JPAAPlainAttr.class);
         this.attribute = (JPAAPlainAttr) attr;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAVirAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAVirAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAVirAttr.java
deleted file mode 100644
index 62e2ea5..0000000
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAVirAttr.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.persistence.jpa.entity.anyobject;
-
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.ManyToOne;
-import javax.persistence.Table;
-import org.apache.syncope.core.persistence.api.entity.anyobject.AVirAttr;
-import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractVirAttr;
-
-@Entity
-@Table(name = JPAAVirAttr.TABLE)
-public class JPAAVirAttr extends AbstractVirAttr<AnyObject> implements AVirAttr {
-
-    private static final long serialVersionUID = -4935990254545760827L;
-
-    public static final String TABLE = "AVirAttr";
-
-    @Id
-    private Long id;
-
-    @ManyToOne
-    private JPAAnyObject owner;
-
-    @Override
-    public Long getKey() {
-        return id;
-    }
-
-    @Override
-    public AnyObject getOwner() {
-        return owner;
-    }
-
-    @Override
-    public void setOwner(final AnyObject owner) {
-        checkType(owner, JPAAnyObject.class);
-        this.owner = (JPAAnyObject) owner;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
index 3e9feda..9d69735 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
@@ -42,7 +42,6 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.ADerAttr;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ARelationship;
-import org.apache.syncope.core.persistence.api.entity.anyobject.AVirAttr;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractAny;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyType;
@@ -52,7 +51,7 @@ import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResour
 @Entity
 @Table(name = JPAAnyObject.TABLE)
 @Cacheable
-public class JPAAnyObject extends AbstractAny<APlainAttr, ADerAttr, AVirAttr> implements AnyObject {
+public class JPAAnyObject extends AbstractAny<APlainAttr, ADerAttr> implements AnyObject {
 
     private static final long serialVersionUID = 9063766472970643492L;
 
@@ -72,10 +71,6 @@ public class JPAAnyObject extends AbstractAny<APlainAttr, ADerAttr, AVirAttr> im
     @Valid
     private List<JPAADerAttr> derAttrs = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
-    @Valid
-    private List<JPAAVirAttr> virAttrs = new ArrayList<>();
-
     @ManyToMany(fetch = FetchType.EAGER)
     @JoinTable(joinColumns =
             @JoinColumn(name = "anyObject_id"),
@@ -149,23 +144,6 @@ public class JPAAnyObject extends AbstractAny<APlainAttr, ADerAttr, AVirAttr> im
     }
 
     @Override
-    public boolean add(final AVirAttr attr) {
-        checkType(attr, JPAAVirAttr.class);
-        return virAttrs.add((JPAAVirAttr) attr);
-    }
-
-    @Override
-    public boolean remove(final AVirAttr attr) {
-        checkType(attr, JPAAVirAttr.class);
-        return virAttrs.remove((JPAAVirAttr) attr);
-    }
-
-    @Override
-    public List<? extends AVirAttr> getVirAttrs() {
-        return virAttrs;
-    }
-
-    @Override
     protected List<JPAExternalResource> internalGetResources() {
         return resources;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
index 4783911..fea5af4 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
@@ -60,7 +60,7 @@ public class JPACPlainAttrUniqueValue extends AbstractPlainAttrValue implements
     }
 
     @Override
-    public void setAttr(final PlainAttr attr) {
+    public void setAttr(final PlainAttr<?> attr) {
         checkType(attr, JPACPlainAttr.class);
         this.attribute = (JPACPlainAttr) attr;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPACPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPACPlainAttrValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPACPlainAttrValue.java
index 2761a84..5b7d2b3 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPACPlainAttrValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPACPlainAttrValue.java
@@ -57,7 +57,7 @@ public class JPACPlainAttrValue extends AbstractPlainAttrValue implements CPlain
     }
 
     @Override
-    public void setAttr(final PlainAttr attr) {
+    public void setAttr(final PlainAttr<?> attr) {
         checkType(attr, JPACPlainAttr.class);
         this.attribute = (JPACPlainAttr) attr;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
index 2b44253..ac5616a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
@@ -37,7 +37,6 @@ import org.apache.syncope.core.persistence.api.entity.DerAttr;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.conf.Conf;
@@ -120,26 +119,6 @@ public class JPAConf extends AbstractAnnotatedEntity<Long> implements Conf {
     }
 
     @Override
-    public boolean add(final VirAttr<?> attr) {
-        return false;
-    }
-
-    @Override
-    public boolean remove(final VirAttr<?> virAttr) {
-        return false;
-    }
-
-    @Override
-    public VirAttr<?> getVirAttr(final String virSchemaName) {
-        return null;
-    }
-
-    @Override
-    public List<? extends VirAttr<?>> getVirAttrs() {
-        return Collections.emptyList();
-    }
-
-    @Override
     public boolean add(final ExternalResource resource) {
         return false;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttrUniqueValue.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttrUniqueValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttrUniqueValue.java
index 3efae7c..a5c1b90 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttrUniqueValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttrUniqueValue.java
@@ -60,7 +60,7 @@ public class JPAGPlainAttrUniqueValue extends AbstractPlainAttrValue implements
     }
 
     @Override
-    public void setAttr(final PlainAttr attr) {
+    public void setAttr(final PlainAttr<?> attr) {
         checkType(attr, JPAGPlainAttr.class);
         this.attribute = (JPAGPlainAttr) attr;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttrValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttrValue.java
index ed93477..e5d0830 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttrValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttrValue.java
@@ -57,7 +57,7 @@ public class JPAGPlainAttrValue extends AbstractPlainAttrValue implements GPlain
     }
 
     @Override
-    public void setAttr(final PlainAttr attr) {
+    public void setAttr(final PlainAttr<?> attr) {
         checkType(attr, JPAGPlainAttr.class);
         this.attribute = (JPAGPlainAttr) attr;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGVirAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGVirAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGVirAttr.java
deleted file mode 100644
index 47b8886..0000000
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGVirAttr.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.persistence.jpa.entity.group;
-
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.ManyToOne;
-import javax.persistence.Table;
-import org.apache.syncope.core.persistence.api.entity.group.GVirAttr;
-import org.apache.syncope.core.persistence.api.entity.group.Group;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractVirAttr;
-
-@Entity
-@Table(name = JPAGVirAttr.TABLE)
-public class JPAGVirAttr extends AbstractVirAttr<Group> implements GVirAttr {
-
-    private static final long serialVersionUID = -1747430556914428649L;
-
-    public static final String TABLE = "GVirAttr";
-
-    @Id
-    private Long id;
-
-    @ManyToOne
-    private JPAGroup owner;
-
-    @Override
-    public Long getKey() {
-        return id;
-    }
-
-    @Override
-    public Group getOwner() {
-        return owner;
-    }
-
-    @Override
-    public void setOwner(final Group owner) {
-        checkType(owner, JPAGroup.class);
-        this.owner = (JPAGroup) owner;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
index 2913dc6..2fb84b5 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
@@ -44,7 +44,6 @@ import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.group.GDerAttr;
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
-import org.apache.syncope.core.persistence.api.entity.group.GVirAttr;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
 import org.apache.syncope.core.persistence.api.entity.user.UDynGroupMembership;
@@ -61,7 +60,7 @@ import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
 @Table(name = JPAGroup.TABLE)
 @Cacheable
 @GroupCheck
-public class JPAGroup extends AbstractAny<GPlainAttr, GDerAttr, GVirAttr> implements Group {
+public class JPAGroup extends AbstractAny<GPlainAttr, GDerAttr> implements Group {
 
     private static final long serialVersionUID = -5281258853142421875L;
 
@@ -88,10 +87,6 @@ public class JPAGroup extends AbstractAny<GPlainAttr, GDerAttr, GVirAttr> implem
     @Valid
     private List<JPAGDerAttr> derAttrs = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
-    @Valid
-    private List<JPAGVirAttr> virAttrs = new ArrayList<>();
-
     @ManyToMany(fetch = FetchType.EAGER)
     @JoinTable(joinColumns =
             @JoinColumn(name = "group_id"),
@@ -205,23 +200,6 @@ public class JPAGroup extends AbstractAny<GPlainAttr, GDerAttr, GVirAttr> implem
     }
 
     @Override
-    public boolean add(final GVirAttr attr) {
-        checkType(attr, JPAGVirAttr.class);
-        return virAttrs.add((JPAGVirAttr) attr);
-    }
-
-    @Override
-    public boolean remove(final GVirAttr attr) {
-        checkType(attr, JPAGVirAttr.class);
-        return virAttrs.remove((JPAGVirAttr) attr);
-    }
-
-    @Override
-    public List<? extends GVirAttr> getVirAttrs() {
-        return virAttrs;
-    }
-
-    @Override
     public ADynGroupMembership getADynMembership() {
         return aDynMembership;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMapping.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMapping.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMapping.java
index 2066f6f..2d7af3c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMapping.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMapping.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.List;
 import javax.persistence.Cacheable;
 import javax.persistence.CascadeType;
+import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.Id;
@@ -48,12 +49,10 @@ public class JPAMapping extends AbstractEntity<Long> implements Mapping {
     @Id
     private Long id;
 
+    @Column(nullable = false)
     @OneToOne
     private JPAProvision provision;
 
-    /**
-     * Attribute mappings.
-     */
     @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "mapping")
     private List<JPAMappingItem> items = new ArrayList<>();
 
@@ -79,17 +78,6 @@ public class JPAMapping extends AbstractEntity<Long> implements Mapping {
     }
 
     @Override
-    public void setConnObjectKeyItem(final MappingItem item) {
-        checkType(item, JPAMappingItem.class);
-        this.addConnObjectKeyItem((JPAMappingItem) item);
-    }
-
-    @Override
-    public List<? extends MappingItem> getItems() {
-        return items;
-    }
-
-    @Override
     public boolean add(final MappingItem item) {
         checkType(item, JPAMappingItem.class);
         return items.contains((JPAMappingItem) item) || items.add((JPAMappingItem) item);
@@ -102,6 +90,11 @@ public class JPAMapping extends AbstractEntity<Long> implements Mapping {
     }
 
     @Override
+    public List<? extends MappingItem> getItems() {
+        return items;
+    }
+
+    @Override
     public MappingItem getConnObjectKeyItem() {
         return CollectionUtils.find(getItems(), new Predicate<MappingItem>() {
 
@@ -112,6 +105,12 @@ public class JPAMapping extends AbstractEntity<Long> implements Mapping {
         });
     }
 
+    @Override
+    public void setConnObjectKeyItem(final MappingItem item) {
+        checkType(item, JPAMappingItem.class);
+        this.addConnObjectKeyItem((JPAMappingItem) item);
+    }
+
     protected boolean addConnObjectKeyItem(final MappingItem connObjectKeyItem) {
         if (IntMappingType.UserVirtualSchema == connObjectKeyItem.getIntMappingType()
                 || IntMappingType.GroupVirtualSchema == connObjectKeyItem.getIntMappingType()

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAProvision.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAProvision.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAProvision.java
index 8e13879..3906dfd 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAProvision.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAProvision.java
@@ -131,5 +131,4 @@ public class JPAProvision extends AbstractEntity<Long> implements Provision {
         checkType(mapping, JPAMapping.class);
         this.mapping = (JPAMapping) mapping;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAPropagationTask.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAPropagationTask.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAPropagationTask.java
index 2bdd0f3..9882752 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAPropagationTask.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAPropagationTask.java
@@ -75,6 +75,8 @@ public class JPAPropagationTask extends AbstractTask implements PropagationTask
     @Enumerated(EnumType.STRING)
     private AnyTypeKind anyTypeKind;
 
+    private String anyType;
+
     private Long anyKey;
 
     public JPAPropagationTask() {
@@ -167,6 +169,16 @@ public class JPAPropagationTask extends AbstractTask implements PropagationTask
     }
 
     @Override
+    public String getAnyType() {
+        return anyType;
+    }
+
+    @Override
+    public void setAnyType(final String anyType) {
+        this.anyType = anyType;
+    }
+
+    @Override
     public Long getAnyKey() {
         return anyKey;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttrUniqueValue.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttrUniqueValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttrUniqueValue.java
index 566739d..86dfdfa 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttrUniqueValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttrUniqueValue.java
@@ -60,7 +60,7 @@ public class JPAUPlainAttrUniqueValue extends AbstractPlainAttrValue implements
     }
 
     @Override
-    public void setAttr(final PlainAttr attr) {
+    public void setAttr(final PlainAttr<?> attr) {
         checkType(attr, JPAUPlainAttr.class);
         this.attribute = (JPAUPlainAttr) attr;
     }


[50/54] [abbrv] syncope git commit: refactoring of the policy stack , SYNCOPE-158

Posted by fm...@apache.org.
refactoring of the policy stack , SYNCOPE-158


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

Branch: refs/heads/SYNCOPE-156
Commit: 79d0316744dd868f3b9a489a4ead6885a8a8d65a
Parents: 15f6d19
Author: massi <ma...@tirasa.net>
Authored: Thu Oct 22 15:44:59 2015 +0200
Committer: massi <ma...@tirasa.net>
Committed: Thu Oct 22 15:45:08 2015 +0200

----------------------------------------------------------------------
 .../client/cli/commands/PolicyCommand.java      | 187 -------------------
 .../cli/commands/policy/PolicyCommand.java      | 111 +++++++++++
 2 files changed, 111 insertions(+), 187 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/79d03167/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
deleted file mode 100644
index fc3a8c0..0000000
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/PolicyCommand.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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.cli.commands;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.ws.WebServiceException;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.cli.Command;
-import org.apache.syncope.client.cli.Input;
-import org.apache.syncope.client.cli.SyncopeServices;
-import org.apache.syncope.client.cli.messages.Messages;
-import org.apache.syncope.client.cli.util.CommandUtils;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
-import org.apache.syncope.common.lib.types.PolicyType;
-import org.apache.syncope.common.rest.api.service.PolicyService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Command(name = "policy")
-public class PolicyCommand extends AbstractCommand {
-
-    private static final Logger LOG = LoggerFactory.getLogger(PolicyCommand.class);
-
-    private static final String HELP_MESSAGE = "Usage: policy [options]\n"
-            + "  Options:\n"
-            + "    --help \n"
-            + "    --list-policy \n"
-            + "       Syntax: --list-policy {POLICY-TYPE} \n"
-            + "          Policy type: ACCOUNT / PASSWORD / SYNC / PUSH\n"
-            + "    --read \n"
-            + "       Syntax: --read {POLICY-ID} {POLICY-ID} [...]\n"
-            + "    --delete \n"
-            + "       Syntax: --delete {POLICY-ID} {POLICY-ID} [...]";
-    
-    @Override
-    public void execute(final Input input) {
-        LOG.debug("Option: {}", input.getOption());
-        LOG.debug("Parameters:");
-        for (final String parameter : input.getParameters()) {
-            LOG.debug("   > " + parameter);
-        }
-
-        final String[] parameters = input.getParameters();
-
-        if (StringUtils.isBlank(input.getOption())) {
-            input.setOption(Options.HELP.getOptionName());
-        }
-
-        final PolicyService policyService = SyncopeServices.get(PolicyService.class);
-        switch (Options.fromName(input.getOption())) {
-            case LIST_POLICY:
-                final String listPolicyErrorMessage = "policy --list-policy {POLICY-TYPE}\n"
-                        + "   Policy type: ACCOUNT / PASSWORD / SYNC / PUSH";
-
-                if (parameters.length == 1) {
-                    try {
-                        for (final AbstractPolicyTO policyTO : policyService.list(PolicyType.valueOf(parameters[0]))) {
-                            System.out.println(policyTO);
-                        }
-                    } catch (final SyncopeClientException ex) {
-                        Messages.printMessage(ex.getMessage());
-                    } catch (final IllegalArgumentException ex) {
-                        Messages.printTypeNotValidMessage(
-                                "policy", input.firstParameter(), CommandUtils.fromEnumToArray(PolicyType.class));
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(listPolicyErrorMessage);
-                }
-                break;
-            case READ:
-                final String readErrorMessage = "policy --read {POLICY-ID} {POLICY-ID} [...]";
-
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            System.out.println(policyService.read(Long.valueOf(parameter)));
-                        } catch (final NumberFormatException ex) {
-                            Messages.printIdNotNumberDeletedMessage("policy", parameter);
-                        } catch (final WebServiceException | SyncopeClientException ex) {
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Policy", parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(readErrorMessage);
-                }
-                break;
-            case DELETE:
-                final String deleteErrorMessage = "policy --delete {POLICY-ID} {POLICY-ID} [...]";
-
-                if (parameters.length >= 1) {
-                    for (final String parameter : parameters) {
-                        try {
-                            policyService.delete(Long.valueOf(parameter));
-                            Messages.printDeletedMessage("Policy", parameter);
-                        } catch (final WebServiceException | SyncopeClientException ex) {
-                            System.out.println("Error:");
-                            if (ex.getMessage().startsWith("NotFound")) {
-                                Messages.printNofFoundMessage("Policy", parameter);
-                            } else if (ex.getMessage().startsWith("DataIntegrityViolation")) {
-                                Messages.printMessage("You cannot delete policy " + parameter);
-                            } else {
-                                Messages.printMessage(ex.getMessage());
-                            }
-                        } catch (final NumberFormatException ex) {
-                            Messages.printIdNotNumberDeletedMessage("policy", parameter);
-                        }
-                    }
-                } else {
-                    Messages.printCommandOptionMessage(deleteErrorMessage);
-                }
-                break;
-            case HELP:
-                System.out.println(HELP_MESSAGE);
-                break;
-            default:
-                Messages.printDefaultMessage(input.getOption(), HELP_MESSAGE);
-        }
-    }
-
-    @Override
-    public String getHelpMessage() {
-        return HELP_MESSAGE;
-    }
-
-    private enum Options {
-
-        HELP("--help"),
-        LIST_POLICY("--list-policy"),
-        READ("--read"),
-        DELETE("--delete");
-
-        private final String optionName;
-
-        Options(final String optionName) {
-            this.optionName = optionName;
-        }
-
-        public String getOptionName() {
-            return optionName;
-        }
-
-        public boolean equalsOptionName(final String otherName) {
-            return (otherName == null) ? false : optionName.equals(otherName);
-        }
-
-        public static Options fromName(final String name) {
-            Options optionToReturn = HELP;
-            for (final Options option : Options.values()) {
-                if (option.equalsOptionName(name)) {
-                    optionToReturn = option;
-                }
-            }
-            return optionToReturn;
-        }
-
-        public static List<String> toList() {
-            final List<String> options = new ArrayList<>();
-            for (final Options value : values()) {
-                options.add(value.getOptionName());
-            }
-            return options;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/79d03167/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyCommand.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyCommand.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyCommand.java
new file mode 100644
index 0000000..7c92d9d
--- /dev/null
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/policy/PolicyCommand.java
@@ -0,0 +1,111 @@
+/*
+ * 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.cli.commands.policy;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.Input;
+import org.apache.syncope.client.cli.commands.AbstractCommand;
+
+@Command(name = "policy")
+public class PolicyCommand extends AbstractCommand {
+
+    private static final String HELP_MESSAGE = "Usage: policy [options]\n"
+            + "  Options:\n"
+            + "    --help \n"
+            + "    --list-policy \n"
+            + "       Syntax: --list-policy {POLICY-TYPE} \n"
+            + "          Policy type: ACCOUNT / PASSWORD / SYNC / PUSH\n"
+            + "    --read \n"
+            + "       Syntax: --read {POLICY-ID} {POLICY-ID} [...]\n"
+            + "    --delete \n"
+            + "       Syntax: --delete {POLICY-ID} {POLICY-ID} [...]";
+
+    @Override
+    public void execute(final Input input) {
+        if (StringUtils.isBlank(input.getOption())) {
+            input.setOption(Options.HELP.getOptionName());
+        }
+
+        switch (Options.fromName(input.getOption())) {
+            case LIST_POLICY:
+                new PolicyList(input).list();
+                break;
+            case READ:
+                new PolicyRead(input).read();
+                break;
+            case DELETE:
+                new PolicyDelete(input).delete();
+                break;
+            case HELP:
+                System.out.println(HELP_MESSAGE);
+                break;
+            default:
+                new PolicyResultManager().defaultError(input.getOption(), HELP_MESSAGE);
+        }
+    }
+
+    @Override
+    public String getHelpMessage() {
+        return HELP_MESSAGE;
+    }
+
+    private enum Options {
+
+        HELP("--help"),
+        LIST_POLICY("--list-policy"),
+        READ("--read"),
+        DELETE("--delete");
+
+        private final String optionName;
+
+        Options(final String optionName) {
+            this.optionName = optionName;
+        }
+
+        public String getOptionName() {
+            return optionName;
+        }
+
+        public boolean equalsOptionName(final String otherName) {
+            return (otherName == null) ? false : optionName.equals(otherName);
+        }
+
+        public static Options fromName(final String name) {
+            Options optionToReturn = HELP;
+            for (final Options option : Options.values()) {
+                if (option.equalsOptionName(name)) {
+                    optionToReturn = option;
+                }
+            }
+            return optionToReturn;
+        }
+
+        public static List<String> toList() {
+            final List<String> options = new ArrayList<>();
+            for (final Options value : values()) {
+                options.add(value.getOptionName());
+            }
+            return options;
+        }
+    }
+
+}


[45/54] [abbrv] syncope git commit: [SYNCOPE-709] Refactoring completed

Posted by fm...@apache.org.
[SYNCOPE-709] Refactoring completed


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

Branch: refs/heads/SYNCOPE-156
Commit: 9cd92305562916453bf2aee42bbc3b6d1b07e5cd
Parents: ef28d8e
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 22 11:41:00 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Oct 22 11:41:00 2015 +0200

----------------------------------------------------------------------
 .../syncope/common/lib/AnyOperations.java       |  26 +-
 .../syncope/common/lib/patch/AnyPatch.java      |   5 +-
 .../org/apache/syncope/common/lib/to/AnyTO.java |   5 +-
 .../syncope/common/lib/to/ProvisionTO.java      |  18 +
 .../syncope/common/lib/to/VirSchemaTO.java      |  20 ++
 .../common/lib/types/PropagationByResource.java |  11 +
 .../syncope/core/logic/ResourceLogic.java       |  36 +-
 .../core/logic/report/StaticReportlet.java      |   4 +-
 .../core/logic/report/UserReportlet.java        |   8 +-
 .../apache/syncope/core/misc/DataFormat.java    | 117 ------
 .../apache/syncope/core/misc/FormatUtils.java   | 117 ++++++
 .../apache/syncope/core/misc/MappingUtils.java  | 172 +++------
 .../syncope/core/misc/jexl/JexlUtils.java       |  35 +-
 .../core/persistence/api/dao/AnyDAO.java        |   2 +-
 .../core/persistence/api/dao/AnySearchDAO.java  |  10 +-
 .../api/dao/ExternalResourceDAO.java            |   5 +-
 .../core/persistence/api/dao/VirAttrDAO.java    |  35 --
 .../core/persistence/api/dao/VirSchemaDAO.java  |   8 +-
 .../core/persistence/api/entity/Any.java        |  10 +-
 .../core/persistence/api/entity/AnyUtils.java   |   6 +-
 .../persistence/api/entity/AnyUtilsFactory.java |   2 +-
 .../core/persistence/api/entity/Attr.java       |   2 +-
 .../core/persistence/api/entity/DerAttr.java    |   2 +-
 .../api/entity/DynGroupMembership.java          |   2 +-
 .../persistence/api/entity/DynMembership.java   |   2 +-
 .../core/persistence/api/entity/Membership.java |   2 +-
 .../core/persistence/api/entity/PlainAttr.java  |   2 +-
 .../persistence/api/entity/Relationship.java    |   2 +-
 .../core/persistence/api/entity/VirAttr.java    |  30 --
 .../core/persistence/api/entity/VirSchema.java  |  13 +
 .../api/entity/anyobject/AVirAttr.java          |  25 --
 .../api/entity/anyobject/AnyObject.java         |   2 +-
 .../core/persistence/api/entity/conf/Conf.java  |   3 +-
 .../persistence/api/entity/group/GVirAttr.java  |  25 --
 .../persistence/api/entity/group/Group.java     |  14 +-
 .../api/entity/task/PropagationTask.java        |   4 +
 .../persistence/api/entity/user/UVirAttr.java   |  25 --
 .../core/persistence/api/entity/user/User.java  |  14 +-
 .../jpa/content/ContentLoaderHandler.java       |   4 +-
 .../jpa/content/XMLContentExporter.java         |  10 +-
 .../persistence/jpa/dao/AbstractAnyDAO.java     |  11 +-
 .../persistence/jpa/dao/JPAAnySearchDAO.java    |  12 +-
 .../core/persistence/jpa/dao/JPADerAttrDAO.java |   2 +-
 .../jpa/dao/JPAExternalResourceDAO.java         |  29 +-
 .../core/persistence/jpa/dao/JPAGroupDAO.java   |   2 +-
 .../persistence/jpa/dao/JPAPlainAttrDAO.java    |   2 +-
 .../jpa/dao/JPAPlainAttrValueDAO.java           |   7 +-
 .../core/persistence/jpa/dao/JPAVirAttrDAO.java |  86 -----
 .../persistence/jpa/dao/JPAVirSchemaDAO.java    |  35 +-
 .../persistence/jpa/entity/AbstractAny.java     |  17 +-
 .../persistence/jpa/entity/AbstractAttr.java    |   2 +-
 .../persistence/jpa/entity/AbstractDerAttr.java |   2 +-
 .../jpa/entity/AbstractDynMembership.java       |   2 +-
 .../jpa/entity/AbstractPlainAttr.java           |   2 +-
 .../jpa/entity/AbstractPlainAttrValue.java      |  18 +-
 .../persistence/jpa/entity/AbstractVirAttr.java |  71 ----
 .../jpa/entity/AnnotatedEntityListener.java     |   4 +-
 .../persistence/jpa/entity/JPAAnyUtils.java     |  52 +--
 .../jpa/entity/JPAAnyUtilsFactory.java          |   2 +-
 .../jpa/entity/JPAEntityFactory.java            |   8 -
 .../persistence/jpa/entity/JPAVirSchema.java    | 147 ++++++++
 .../anyobject/JPAAPlainAttrUniqueValue.java     |   2 +-
 .../entity/anyobject/JPAAPlainAttrValue.java    |   2 +-
 .../jpa/entity/anyobject/JPAAVirAttr.java       |  59 ---
 .../jpa/entity/anyobject/JPAAnyObject.java      |  24 +-
 .../entity/conf/JPACPlainAttrUniqueValue.java   |   2 +-
 .../jpa/entity/conf/JPACPlainAttrValue.java     |   2 +-
 .../persistence/jpa/entity/conf/JPAConf.java    |  21 --
 .../entity/group/JPAGPlainAttrUniqueValue.java  |   2 +-
 .../jpa/entity/group/JPAGPlainAttrValue.java    |   2 +-
 .../jpa/entity/group/JPAGVirAttr.java           |  59 ---
 .../persistence/jpa/entity/group/JPAGroup.java  |  24 +-
 .../jpa/entity/resource/JPAMapping.java         |  27 +-
 .../jpa/entity/resource/JPAProvision.java       |   1 -
 .../jpa/entity/task/JPAPropagationTask.java     |  12 +
 .../entity/user/JPAUPlainAttrUniqueValue.java   |   2 +-
 .../jpa/entity/user/JPAUPlainAttrValue.java     |   2 +-
 .../jpa/entity/user/JPAUVirAttr.java            |  59 ---
 .../persistence/jpa/entity/user/JPAUser.java    |  24 +-
 .../entity/ExternalResourceValidator.java       |  45 ++-
 .../jpa/validation/entity/PlainAttrCheck.java   |   2 +-
 .../validation/entity/PlainAttrValidator.java   |   2 +-
 .../resources/META-INF/spring-orm-oracle.xml    |  25 --
 .../resources/META-INF/spring-orm-sqlserver.xml |  25 --
 .../src/main/resources/META-INF/spring-orm.xml  |  25 --
 .../src/main/resources/indexes.xml              |   4 -
 .../persistence/jpa/inner/PlainAttrTest.java    |   1 -
 .../persistence/jpa/inner/ResourceTest.java     |  46 +++
 .../core/persistence/jpa/inner/TaskTest.java    |   1 +
 .../core/persistence/jpa/inner/VirAttrTest.java | 118 ------
 .../persistence/jpa/inner/VirSchemaTest.java    |  12 +-
 .../persistence/jpa/outer/ResourceTest.java     |  15 +-
 .../core/persistence/jpa/outer/TaskTest.java    |   1 +
 .../persistence/jpa/outer/VirSchemaTest.java    |  76 ++++
 .../test/resources/domains/MasterContent.xml    |  29 +-
 .../core/provisioning/api/Connector.java        |  27 +-
 .../core/provisioning/api/VirAttrHandler.java   |  52 +--
 .../api/cache/VirAttrCacheValue.java            |  36 +-
 .../api/propagation/PropagationManager.java     |   5 +-
 .../core/provisioning/api/sync/PushActions.java |  20 +-
 .../provisioning/java/ConnectorFacadeProxy.java |  29 +-
 .../DefaultAnyObjectProvisioningManager.java    |  12 -
 .../java/DefaultGroupProvisioningManager.java   |  12 -
 .../java/DefaultUserProvisioningManager.java    |  30 +-
 .../provisioning/java/VirAttrHandlerImpl.java   | 356 ++++---------------
 .../java/data/AbstractAnyDataBinder.java        | 138 +++----
 .../java/data/AnyObjectDataBinderImpl.java      |  11 +-
 .../java/data/GroupDataBinderImpl.java          |  11 +-
 .../java/data/ResourceDataBinderImpl.java       |  48 ++-
 .../java/data/SchemaDataBinderImpl.java         |  16 +-
 .../java/data/UserDataBinderImpl.java           |  11 +-
 .../core/provisioning/java/job/TaskJob.java     |   4 +-
 .../notification/NotificationManagerImpl.java   |  26 +-
 .../AbstractPropagationTaskExecutor.java        |  89 +++--
 .../propagation/PropagationManagerImpl.java     | 248 +++++++------
 .../java/sync/AbstractPushResultHandler.java    |  57 +--
 .../java/sync/AbstractSyncResultHandler.java    |  42 ++-
 .../java/sync/AbstractSyncopeResultHandler.java |   2 +-
 .../sync/AnyObjectPushResultHandlerImpl.java    |   4 +-
 .../sync/AnyObjectSyncResultHandlerImpl.java    |   2 +-
 .../java/sync/DefaultPushActions.java           |  16 +-
 .../java/sync/GroupPushResultHandlerImpl.java   |   4 +-
 .../java/sync/GroupSyncResultHandlerImpl.java   |   2 +-
 .../provisioning/java/sync/PushJobDelegate.java |   4 +-
 .../provisioning/java/sync/SyncJobDelegate.java |  31 +-
 .../core/provisioning/java/sync/SyncUtils.java  |  12 +-
 .../java/sync/UserPushResultHandlerImpl.java    |   6 +-
 .../java/sync/UserSyncResultHandlerImpl.java    |   2 +-
 .../rest/cxf/ThreadLocalCleanupListener.java    |   4 +-
 .../rest/cxf/service/AbstractAnyService.java    |   9 +-
 .../processor/AnyObjectUpdateProcessor.java     |  13 -
 .../camel/processor/GroupUpdateProcessor.java   |  13 -
 .../processor/UserUpdateInSyncProcessor.java    |   6 +-
 .../camel/processor/UserUpdateProcessor.java    |  27 +-
 fit/console-reference/pom.xml                   |  81 +----
 fit/core-reference/pom.xml                      |  16 +-
 .../syncope/fit/core/reference/GroupITCase.java |  26 +-
 .../core/reference/PropagationTaskITCase.java   |   8 -
 .../fit/core/reference/SyncTaskITCase.java      |  20 +-
 .../syncope/fit/core/reference/UserITCase.java  |  53 +--
 .../fit/core/reference/VirAttrITCase.java       | 329 +++++++++--------
 .../fit/core/reference/VirSchemaITCase.java     |  41 ++-
 142 files changed, 1609 insertions(+), 2503 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
index e1f9f88..0e5bec3 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
@@ -150,29 +150,8 @@ public final class AnyOperations {
         }
 
         // 5. virtual attributes
-        updatedAttrs = updated.getVirAttrMap();
-        originalAttrs = original.getVirAttrMap();
-
         result.getVirAttrs().clear();
-
-        if (!incremental) {
-            CollectionUtils.forAllDo(CollectionUtils.subtract(originalAttrs.keySet(), updatedAttrs.keySet()),
-                    new Closure<String>() {
-
-                        @Override
-                        public void execute(final String schema) {
-                            result.getVirAttrs().add(new AttrPatch.Builder().
-                                    operation(PatchOperation.DELETE).
-                                    attrTO(new AttrTO.Builder().schema(schema).build()).
-                                    build());
-                        }
-                    });
-        }
-
-        for (AttrTO attrTO : updatedAttrs.values()) {
-            AttrPatch patch = new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).attrTO(attrTO).build();
-            result.getVirAttrs().add(patch);
-        }
+        result.getVirAttrs().addAll(updated.getVirAttrs());
 
         // 6. resources
         result.getResources().clear();
@@ -188,7 +167,6 @@ public final class AnyOperations {
             result.getResources().add(
                     new StringPatchItem.Builder().operation(PatchOperation.ADD_REPLACE).value(resource).build());
         }
-
     }
 
     /**
@@ -450,7 +428,7 @@ public final class AnyOperations {
 
         // 4. virtual attributes
         result.getVirAttrs().clear();
-        result.getVirAttrs().addAll(AnyOperations.patch(to.getVirAttrMap(), patch.getVirAttrs()));
+        result.getVirAttrs().addAll(patch.getVirAttrs());
 
         // 5. resources
         for (StringPatchItem resourcePatch : patch.getResources()) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
index e4b9e87..a6c4323 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
@@ -27,6 +27,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlType;
 import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.to.AttrTO;
 
 @XmlType
 public abstract class AnyPatch extends AbstractBaseBean {
@@ -43,7 +44,7 @@ public abstract class AnyPatch extends AbstractBaseBean {
 
     private final Set<AttrPatch> derAttrs = new HashSet<>();
 
-    private final Set<AttrPatch> virAttrs = new HashSet<>();
+    private final Set<AttrTO> virAttrs = new HashSet<>();
 
     private final Set<StringPatchItem> resources = new HashSet<>();
 
@@ -88,7 +89,7 @@ public abstract class AnyPatch extends AbstractBaseBean {
     @XmlElementWrapper(name = "virAttrs")
     @XmlElement(name = "attribute")
     @JsonProperty("virAttrs")
-    public Set<AttrPatch> getVirAttrs() {
+    public Set<AttrTO> getVirAttrs() {
         return virAttrs;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
index 56b1c44..7911d7d 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
@@ -25,7 +25,6 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -53,9 +52,9 @@ public abstract class AnyTO extends ConnObjectTO {
 
     private final List<String> auxClasses = new ArrayList<>();
 
-    private final Set<AttrTO> derAttrs = new LinkedHashSet<>();
+    private final Set<AttrTO> derAttrs = new HashSet<>();
 
-    private final Set<AttrTO> virAttrs = new LinkedHashSet<>();
+    private final Set<AttrTO> virAttrs = new HashSet<>();
 
     private final Set<String> resources = new HashSet<>();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisionTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisionTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisionTO.java
index c4ff740..b25053d 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisionTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisionTO.java
@@ -18,8 +18,17 @@
  */
 package org.apache.syncope.common.lib.to;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
 import org.apache.syncope.common.lib.AbstractBaseBean;
 
+@XmlRootElement(name = "provision")
+@XmlType
 public class ProvisionTO extends AbstractBaseBean {
 
     private static final long serialVersionUID = 8298910216218007927L;
@@ -34,6 +43,8 @@ public class ProvisionTO extends AbstractBaseBean {
 
     private MappingTO mapping;
 
+    private List<String> virSchemas = new ArrayList<>();
+
     public long getKey() {
         return key;
     }
@@ -74,4 +85,11 @@ public class ProvisionTO extends AbstractBaseBean {
         this.mapping = mapping;
     }
 
+    @XmlElementWrapper(name = "virSchemas")
+    @XmlElement(name = "virSchema")
+    @JsonProperty("virSchemas")
+    public List<String> getVirSchemas() {
+        return virSchemas;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/common/lib/src/main/java/org/apache/syncope/common/lib/to/VirSchemaTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/VirSchemaTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/VirSchemaTO.java
index 1a9d3bd..8c3df1b 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/VirSchemaTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/VirSchemaTO.java
@@ -27,6 +27,10 @@ public class VirSchemaTO extends AbstractSchemaTO {
 
     private boolean readonly;
 
+    private long provision;
+
+    private String extAttrName;
+
     public boolean isReadonly() {
         return readonly;
     }
@@ -35,4 +39,20 @@ public class VirSchemaTO extends AbstractSchemaTO {
         this.readonly = readonly;
     }
 
+    public long getProvision() {
+        return provision;
+    }
+
+    public void setProvision(final long provision) {
+        this.provision = provision;
+    }
+
+    public String getExtAttrName() {
+        return extAttrName;
+    }
+
+    public void setExtAttrName(final String extAttrName) {
+        this.extAttrName = extAttrName;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/common/lib/src/main/java/org/apache/syncope/common/lib/types/PropagationByResource.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/PropagationByResource.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/PropagationByResource.java
index bf35bb3..3e35fec 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/PropagationByResource.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/PropagationByResource.java
@@ -263,6 +263,17 @@ public class PropagationByResource implements Serializable {
         return result;
     }
 
+    public Map<String, ResourceOperation> asMap() {
+        Map<String, ResourceOperation> result = new HashMap<>();
+        for (ResourceOperation operation : ResourceOperation.values()) {
+            for (String resourceName : get(operation)) {
+                result.put(resourceName, operation);
+            }
+        }
+
+        return result;
+    }
+
     /**
      * Set resources for a given resource operation type.
      *

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index c3ce0c6..44a5aa8 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -20,9 +20,12 @@ package org.apache.syncope.core.logic;
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IteratorUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.ArrayUtils;
@@ -51,9 +54,11 @@ import org.apache.syncope.core.misc.ConnObjectUtils;
 import org.apache.syncope.core.misc.MappingUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeUtil;
@@ -86,6 +91,9 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     private GroupDAO groupDAO;
 
     @Autowired
+    private VirSchemaDAO virSchemaDAO;
+
+    @Autowired
     private ResourceDataBinder binder;
 
     @Autowired
@@ -205,7 +213,8 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     public ConnObjectTO readConnObject(final String key, final String anyTypeKey, final Long anyKey) {
         Triple<ExternalResource, AnyType, Provision> init = connObjectInit(key, anyTypeKey);
 
-        Any<?, ?, ?> any = init.getMiddle().getKind() == AnyTypeKind.USER
+        // 1. find any
+        Any<?, ?> any = init.getMiddle().getKind() == AnyTypeKind.USER
                 ? userDAO.find(anyKey)
                 : init.getMiddle().getKind() == AnyTypeKind.ANY_OBJECT
                         ? anyObjectDAO.find(anyKey)
@@ -213,6 +222,8 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
         if (any == null) {
             throw new NotFoundException(init.getMiddle() + " " + anyKey);
         }
+
+        // 2. build connObjectKeyItem
         MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(init.getRight());
         if (connObjectKeyItem == null) {
             throw new NotFoundException(
@@ -220,17 +231,28 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
         }
         String connObjectKeyValue = mappingUtils.getConnObjectKeyValue(any, init.getRight());
 
+        // 3. determine attributes to query
+        Set<MappingItem> linkinMappingItems = new HashSet<>();
+        for (VirSchema virSchema : virSchemaDAO.findByProvision(init.getRight())) {
+            linkinMappingItems.add(virSchema.asLinkingMappingItem());
+        }
+        Iterator<MappingItem> mapItems = IteratorUtils.chainedIterator(
+                init.getRight().getMapping().getItems().iterator(),
+                linkinMappingItems.iterator());
+
+        // 4. read from the underlying connector
         Connector connector = connFactory.getConnector(init.getLeft());
         ConnectorObject connectorObject = connector.getObject(
                 init.getRight().getObjectClass(),
                 new Uid(connObjectKeyValue),
-                connector.getOperationOptions(MappingUtils.getBothMappingItems(init.getRight())));
+                connector.getOperationOptions(mapItems));
         if (connectorObject == null) {
             throw new NotFoundException(
                     "Object " + connObjectKeyValue + " with class " + init.getRight().getObjectClass()
                     + " not found on resource " + key);
         }
 
+        // 5. build result
         Set<Attribute> attributes = connectorObject.getAttributes();
         if (AttributeUtil.find(Uid.NAME, attributes) == null) {
             attributes.add(connectorObject.getUid());
@@ -251,6 +273,14 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
 
         Connector connector = connFactory.getConnector(init.getLeft());
 
+        Set<MappingItem> linkinMappingItems = new HashSet<>();
+        for (VirSchema virSchema : virSchemaDAO.findByProvision(init.getRight())) {
+            linkinMappingItems.add(virSchema.asLinkingMappingItem());
+        }
+        Iterator<MappingItem> mapItems = IteratorUtils.chainedIterator(
+                init.getRight().getMapping().getItems().iterator(),
+                linkinMappingItems.iterator());
+
         final SearchResult[] searchResult = new SearchResult[1];
         final List<ConnObjectTO> connObjects = new ArrayList<>();
         connector.search(init.getRight().getObjectClass(), null, new SearchResultsHandler() {
@@ -265,7 +295,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
                 connObjects.add(connObjectUtils.getConnObjectTO(connectorObject));
                 return true;
             }
-        }, size, pagedResultsCookie, orderBy);
+        }, size, pagedResultsCookie, orderBy, mapItems);
 
         return ImmutablePair.of(searchResult[0], connObjects);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/logic/src/main/java/org/apache/syncope/core/logic/report/StaticReportlet.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/report/StaticReportlet.java b/core/logic/src/main/java/org/apache/syncope/core/logic/report/StaticReportlet.java
index b7db39f..0e785b1 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/report/StaticReportlet.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/report/StaticReportlet.java
@@ -21,7 +21,7 @@ package org.apache.syncope.core.logic.report;
 import org.apache.syncope.core.persistence.api.dao.ReportletConfClass;
 import org.apache.syncope.common.lib.report.ReportletConf;
 import org.apache.syncope.common.lib.report.StaticReportletConf;
-import org.apache.syncope.core.misc.DataFormat;
+import org.apache.syncope.core.misc.FormatUtils;
 import org.springframework.util.StringUtils;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
@@ -101,7 +101,7 @@ public class StaticReportlet extends AbstractReportlet {
 
         if (this.conf.getDateField() != null) {
             handler.startElement("", "", "date", null);
-            String printed = DataFormat.format(this.conf.getDateField());
+            String printed = FormatUtils.format(this.conf.getDateField());
             handler.characters(printed.toCharArray(), 0, printed.length());
             handler.endElement("", "", "date");
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/logic/src/main/java/org/apache/syncope/core/logic/report/UserReportlet.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/report/UserReportlet.java b/core/logic/src/main/java/org/apache/syncope/core/logic/report/UserReportlet.java
index c11ca05..3eb96b3 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/report/UserReportlet.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/report/UserReportlet.java
@@ -38,7 +38,7 @@ import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.misc.search.SearchCondConverter;
-import org.apache.syncope.core.misc.DataFormat;
+import org.apache.syncope.core.misc.FormatUtils;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
 import org.apache.syncope.core.persistence.api.entity.user.URelationship;
@@ -231,21 +231,21 @@ public class UserReportlet extends AbstractReportlet {
                         type = ReportXMLConst.XSD_DATETIME;
                         value = user.getCreationDate() == null
                                 ? ""
-                                : DataFormat.format(user.getCreationDate());
+                                : FormatUtils.format(user.getCreationDate());
                         break;
 
                     case lastLoginDate:
                         type = ReportXMLConst.XSD_DATETIME;
                         value = user.getLastLoginDate() == null
                                 ? ""
-                                : DataFormat.format(user.getLastLoginDate());
+                                : FormatUtils.format(user.getLastLoginDate());
                         break;
 
                     case changePwdDate:
                         type = ReportXMLConst.XSD_DATETIME;
                         value = user.getChangePwdDate() == null
                                 ? ""
-                                : DataFormat.format(user.getChangePwdDate());
+                                : FormatUtils.format(user.getChangePwdDate());
                         break;
 
                     case passwordHistorySize:

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/misc/src/main/java/org/apache/syncope/core/misc/DataFormat.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/DataFormat.java b/core/misc/src/main/java/org/apache/syncope/core/misc/DataFormat.java
deleted file mode 100644
index fded378..0000000
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/DataFormat.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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.misc;
-
-import java.text.DecimalFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import org.apache.commons.lang3.time.DateUtils;
-import org.apache.syncope.common.lib.SyncopeConstants;
-
-/**
- * Utility class for parsing / formatting date and numbers.
- */
-public final class DataFormat {
-
-    private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
-
-        @Override
-        protected SimpleDateFormat initialValue() {
-            SimpleDateFormat sdf = new SimpleDateFormat();
-            sdf.applyPattern(SyncopeConstants.DEFAULT_DATE_PATTERN);
-            return sdf;
-        }
-    };
-
-    private static final ThreadLocal<DecimalFormat> DECIMAL_FORMAT = new ThreadLocal<DecimalFormat>() {
-
-        @Override
-        protected DecimalFormat initialValue() {
-            return new DecimalFormat();
-        }
-    };
-
-    public static String format(final Date date) {
-        return format(date, true);
-    }
-
-    public static String format(final Date date, final boolean lenient) {
-        return format(date, lenient, null);
-    }
-
-    public static String format(final Date date, final boolean lenient, final String conversionPattern) {
-        SimpleDateFormat sdf = DATE_FORMAT.get();
-        if (conversionPattern != null) {
-            sdf.applyPattern(conversionPattern);
-        }
-        sdf.setLenient(lenient);
-        return sdf.format(date);
-    }
-
-    public static String format(final long number) {
-        return format(number, null);
-    }
-
-    public static String format(final long number, final String conversionPattern) {
-        DecimalFormat df = DECIMAL_FORMAT.get();
-        if (conversionPattern != null) {
-            df.applyPattern(conversionPattern);
-        }
-        return df.format(number);
-    }
-
-    public static String format(final double number) {
-        return format(number, null);
-    }
-
-    public static String format(final double number, final String conversionPattern) {
-        DecimalFormat df = DECIMAL_FORMAT.get();
-        if (conversionPattern != null) {
-            df.applyPattern(conversionPattern);
-        }
-        return df.format(number);
-    }
-
-    public static Date parseDate(final String source) throws ParseException {
-        return DateUtils.parseDate(source, SyncopeConstants.DATE_PATTERNS);
-    }
-
-    public static Date parseDate(final String source, final String conversionPattern) throws ParseException {
-        SimpleDateFormat sdf = DATE_FORMAT.get();
-        sdf.applyPattern(conversionPattern);
-        sdf.setLenient(false);
-        return sdf.parse(source);
-    }
-
-    public static Number parseNumber(final String source, final String conversionPattern) throws ParseException {
-        DecimalFormat df = DECIMAL_FORMAT.get();
-        df.applyPattern(conversionPattern);
-        return df.parse(source);
-    }
-
-    public static void clear() {
-        DATE_FORMAT.remove();
-        DECIMAL_FORMAT.remove();
-    }
-
-    private DataFormat() {
-        // private empty constructor
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/misc/src/main/java/org/apache/syncope/core/misc/FormatUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/FormatUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/FormatUtils.java
new file mode 100644
index 0000000..0b06906
--- /dev/null
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/FormatUtils.java
@@ -0,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.core.misc;
+
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.apache.commons.lang3.time.DateUtils;
+import org.apache.syncope.common.lib.SyncopeConstants;
+
+/**
+ * Utility class for parsing / formatting date and numbers.
+ */
+public final class FormatUtils {
+
+    private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
+
+        @Override
+        protected SimpleDateFormat initialValue() {
+            SimpleDateFormat sdf = new SimpleDateFormat();
+            sdf.applyPattern(SyncopeConstants.DEFAULT_DATE_PATTERN);
+            return sdf;
+        }
+    };
+
+    private static final ThreadLocal<DecimalFormat> DECIMAL_FORMAT = new ThreadLocal<DecimalFormat>() {
+
+        @Override
+        protected DecimalFormat initialValue() {
+            return new DecimalFormat();
+        }
+    };
+
+    public static String format(final Date date) {
+        return format(date, true);
+    }
+
+    public static String format(final Date date, final boolean lenient) {
+        return format(date, lenient, null);
+    }
+
+    public static String format(final Date date, final boolean lenient, final String conversionPattern) {
+        SimpleDateFormat sdf = DATE_FORMAT.get();
+        if (conversionPattern != null) {
+            sdf.applyPattern(conversionPattern);
+        }
+        sdf.setLenient(lenient);
+        return sdf.format(date);
+    }
+
+    public static String format(final long number) {
+        return format(number, null);
+    }
+
+    public static String format(final long number, final String conversionPattern) {
+        DecimalFormat df = DECIMAL_FORMAT.get();
+        if (conversionPattern != null) {
+            df.applyPattern(conversionPattern);
+        }
+        return df.format(number);
+    }
+
+    public static String format(final double number) {
+        return format(number, null);
+    }
+
+    public static String format(final double number, final String conversionPattern) {
+        DecimalFormat df = DECIMAL_FORMAT.get();
+        if (conversionPattern != null) {
+            df.applyPattern(conversionPattern);
+        }
+        return df.format(number);
+    }
+
+    public static Date parseDate(final String source) throws ParseException {
+        return DateUtils.parseDate(source, SyncopeConstants.DATE_PATTERNS);
+    }
+
+    public static Date parseDate(final String source, final String conversionPattern) throws ParseException {
+        SimpleDateFormat sdf = DATE_FORMAT.get();
+        sdf.applyPattern(conversionPattern);
+        sdf.setLenient(false);
+        return sdf.parse(source);
+    }
+
+    public static Number parseNumber(final String source, final String conversionPattern) throws ParseException {
+        DecimalFormat df = DECIMAL_FORMAT.get();
+        df.applyPattern(conversionPattern);
+        return df.parse(source);
+    }
+
+    public static void clear() {
+        DATE_FORMAT.remove();
+        DECIMAL_FORMAT.remove();
+    }
+
+    private FormatUtils() {
+        // private empty constructor
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
index 085f07d..54a4428 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
@@ -19,15 +19,11 @@
 package org.apache.syncope.core.misc;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
-import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.ListUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.commons.jexl2.JexlContext;
 import org.apache.commons.jexl2.MapContext;
 import org.apache.commons.lang3.ClassUtils;
@@ -35,7 +31,6 @@ import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.GroupTO;
@@ -53,7 +48,6 @@ import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
@@ -70,6 +64,7 @@ import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Schema;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
@@ -122,42 +117,6 @@ public class MappingUtils {
     @Autowired
     private AnyUtilsFactory anyUtilsFactory;
 
-    public static <T extends MappingItem> Collection<T> getMatchingMappingItems(
-            final Collection<T> items, final IntMappingType type) {
-
-        return CollectionUtils.select(items, new Predicate<T>() {
-
-            @Override
-            public boolean evaluate(final T item) {
-                return item.getIntMappingType() == type;
-            }
-        });
-    }
-
-    public static <T extends MappingItem> Collection<T> getMatchingMappingItems(
-            final Collection<T> items, final String intAttrName, final IntMappingType type) {
-
-        return CollectionUtils.select(items, new Predicate<T>() {
-
-            @Override
-            public boolean evaluate(final T item) {
-                return item.getIntMappingType() == type && intAttrName.equals(item.getIntAttrName());
-            }
-        });
-    }
-
-    public static <T extends MappingItem> Collection<T> getMatchingMappingItems(
-            final Collection<T> items, final String intAttrName) {
-
-        return CollectionUtils.select(items, new Predicate<T>() {
-
-            @Override
-            public boolean evaluate(final T item) {
-                return intAttrName.equals(item.getIntAttrName());
-            }
-        });
-    }
-
     public static MappingItem getConnObjectKeyItem(final Provision provision) {
         Mapping mapping = null;
         if (provision != null) {
@@ -241,7 +200,7 @@ public class MappingUtils {
      * @param connObjectKey connector object key
      * @return the value to be propagated as __NAME__
      */
-    public static Name evaluateNAME(final Any<?, ?, ?> any, final Provision provision, final String connObjectKey) {
+    public static Name evaluateNAME(final Any<?, ?> any, final Provision provision, final String connObjectKey) {
         if (StringUtils.isBlank(connObjectKey)) {
             // LOG error but avoid to throw exception: leave it to the external resource
             LOG.error("Missing ConnObjectKey for '{}': ", provision.getResource());
@@ -302,17 +261,15 @@ public class MappingUtils {
      * @param any given any object
      * @param password clear-text password
      * @param changePwd whether password should be included for propagation attributes or not
-     * @param vAttrs virtual attributes to be managed
      * @param enable whether any object must be enabled or not
      * @param provision provision information
      * @return connObjectLink + prepared attributes
      */
     @Transactional(readOnly = true)
     public Pair<String, Set<Attribute>> prepareAttrs(
-            final Any<?, ?, ?> any,
+            final Any<?, ?> any,
             final String password,
             final boolean changePwd,
-            final Map<String, AttrPatch> vAttrs,
             final Boolean enable,
             final Provision provision) {
 
@@ -322,19 +279,11 @@ public class MappingUtils {
         Set<Attribute> attributes = new HashSet<>();
         String connObjectKey = null;
 
-        for (MappingItem mapping : getMappingItems(provision, MappingPurpose.PROPAGATION)) {
-            LOG.debug("Processing schema {}", mapping.getIntAttrName());
+        for (MappingItem mappingItem : getMappingItems(provision, MappingPurpose.PROPAGATION)) {
+            LOG.debug("Processing schema {}", mappingItem.getIntAttrName());
 
             try {
-                if (mapping.getIntMappingType() == IntMappingType.UserVirtualSchema
-                        || mapping.getIntMappingType() == IntMappingType.GroupVirtualSchema
-                        || mapping.getIntMappingType() == IntMappingType.AnyObjectVirtualSchema) {
-
-                    LOG.debug("Expire entry cache {}-{}", any.getKey(), mapping.getIntAttrName());
-                    virAttrCache.expire(any.getType().getKey(), any.getKey(), mapping.getIntAttrName());
-                }
-
-                Pair<String, Attribute> preparedAttr = prepareAttr(provision, mapping, any, password, vAttrs);
+                Pair<String, Attribute> preparedAttr = prepareAttr(provision, mappingItem, any, password);
 
                 if (preparedAttr != null && preparedAttr.getKey() != null) {
                     connObjectKey = preparedAttr.getKey();
@@ -355,7 +304,7 @@ public class MappingUtils {
                     }
                 }
             } catch (Exception e) {
-                LOG.debug("Attribute '{}' processing failed", mapping.getIntAttrName(), e);
+                LOG.debug("Attribute '{}' processing failed", mappingItem.getIntAttrName(), e);
             }
         }
 
@@ -387,15 +336,12 @@ public class MappingUtils {
      * @param mapItem mapping item for the given attribute
      * @param any any object
      * @param password clear-text password
-     * @param vAttrs virtual attributes to be managed
      * @return connObjectLink + prepared attribute
      */
     private Pair<String, Attribute> prepareAttr(
-            final Provision provision, final MappingItem mapItem,
-            final Any<?, ?, ?> any, final String password,
-            final Map<String, AttrPatch> vAttrs) {
+            final Provision provision, final MappingItem mapItem, final Any<?, ?> any, final String password) {
 
-        List<Any<?, ?, ?>> anys = new ArrayList<>();
+        List<Any<?, ?>> anys = new ArrayList<>();
 
         switch (mapItem.getIntMappingType().getAnyTypeKind()) {
             case USER:
@@ -407,7 +353,6 @@ public class MappingUtils {
             case GROUP:
                 if (any instanceof User) {
                     for (Group group : userDAO.findAllGroups((User) any)) {
-                        virAttrHandler.retrieveVirAttrValues(group);
                         anys.add(group);
                     }
                 } else if (any instanceof Group) {
@@ -424,8 +369,6 @@ public class MappingUtils {
             default:
         }
 
-        List<PlainAttrValue> values = getIntValues(provision, mapItem, anys, vAttrs);
-
         Schema schema = null;
         boolean readOnlyVirSchema = false;
         AttrSchemaType schemaType;
@@ -453,6 +396,8 @@ public class MappingUtils {
 
         String extAttrName = mapItem.getExtAttrName();
 
+        List<PlainAttrValue> values = getIntValues(provision, mapItem, anys);
+
         LOG.debug("Define mapping for: "
                 + "\n* ExtAttrName " + extAttrName
                 + "\n* is connObjectKey " + mapItem.isConnObjectKey()
@@ -501,8 +446,7 @@ public class MappingUtils {
                     result = null;
                 } else {
                     result = new ImmutablePair<>(
-                            null,
-                            AttributeBuilder.buildPassword(passwordAttrValue.toCharArray()));
+                            null, AttributeBuilder.buildPassword(passwordAttrValue.toCharArray()));
                 }
             } else {
                 if ((schema != null && schema.isMultivalue())
@@ -510,8 +454,7 @@ public class MappingUtils {
                         != mapItem.getIntMappingType().getAnyTypeKind()) {
 
                     result = new ImmutablePair<>(
-                            null,
-                            AttributeBuilder.build(extAttrName, objValues));
+                            null, AttributeBuilder.build(extAttrName, objValues));
                 } else {
                     result = new ImmutablePair<>(
                             null, objValues.isEmpty()
@@ -524,9 +467,8 @@ public class MappingUtils {
         return result;
     }
 
-    private String getGroupOwnerValue(final Provision provision, final Any<?, ?, ?> any) {
-        Pair<String, Attribute> preparedAttr = prepareAttr(
-                provision, getConnObjectKeyItem(provision), any, null, Collections.<String, AttrPatch>emptyMap());
+    private String getGroupOwnerValue(final Provision provision, final Any<?, ?> any) {
+        Pair<String, Attribute> preparedAttr = prepareAttr(provision, getConnObjectKeyItem(provision), any, null);
         String connObjectKey = preparedAttr.getKey();
 
         return evaluateNAME(any, provision, connObjectKey).getNameValue();
@@ -538,12 +480,11 @@ public class MappingUtils {
      * @param provision provision information
      * @param mappingItem mapping item
      * @param anys any objects
-     * @param vAttrs virtual attributes to be managed
      * @return attribute values.
      */
     @Transactional(readOnly = true)
     public List<PlainAttrValue> getIntValues(final Provision provision,
-            final MappingItem mappingItem, final List<Any<?, ?, ?>> anys, final Map<String, AttrPatch> vAttrs) {
+            final MappingItem mappingItem, final List<Any<?, ?>> anys) {
 
         LOG.debug("Get attributes for '{}' and mapping type '{}'", anys, mappingItem.getIntMappingType());
 
@@ -554,7 +495,7 @@ public class MappingUtils {
             case UserPlainSchema:
             case GroupPlainSchema:
             case AnyObjectPlainSchema:
-                for (Any<?, ?, ?> any : anys) {
+                for (Any<?, ?> any : anys) {
                     PlainAttr<?> attr = any.getPlainAttr(mappingItem.getIntAttrName());
                     if (attr != null) {
                         if (attr.getUniqueValue() != null) {
@@ -579,46 +520,10 @@ public class MappingUtils {
 
                 break;
 
-            case UserVirtualSchema:
-            case GroupVirtualSchema:
-            case AnyObjectVirtualSchema:
-                // virtual attributes don't get transformed
-                transform = false;
-
-                for (Any<?, ?, ?> any : anys) {
-                    AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
-                    VirAttr<?> attr = any.getVirAttr(mappingItem.getIntAttrName());
-                    if (attr != null) {
-                        if (vAttrs != null) {
-                            if (vAttrs.containsKey(mappingItem.getIntAttrName())) {
-                                attr.getValues().clear();
-                                attr.getValues().addAll(
-                                        vAttrs.get(mappingItem.getIntAttrName()).getAttrTO().getValues());
-                            } else {
-                                throw new IllegalArgumentException("Don't need to update virtual attribute '"
-                                        + mappingItem.getIntAttrName() + "'");
-                            }
-                        }
-                        for (String value : attr.getValues()) {
-                            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-                            attrValue.setStringValue(value);
-                            values.add(attrValue);
-                        }
-                    }
-
-                    LOG.debug("Retrieved {} virtual attribute {}"
-                            + "\n* IntAttrName {}"
-                            + "\n* IntMappingType {}"
-                            + "\n* Attribute values {}",
-                            any.getClass().getSimpleName(),
-                            attr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
-                }
-                break;
-
             case UserDerivedSchema:
             case GroupDerivedSchema:
             case AnyObjectDerivedSchema:
-                for (Any<?, ?, ?> any : anys) {
+                for (Any<?, ?> any : anys) {
                     AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
                     DerAttr<?> attr = any.getDerAttr(mappingItem.getIntAttrName());
                     if (attr != null) {
@@ -635,10 +540,39 @@ public class MappingUtils {
                 }
                 break;
 
+            case UserVirtualSchema:
+            case GroupVirtualSchema:
+            case AnyObjectVirtualSchema:
+                // virtual attributes don't get transformed
+                transform = false;
+
+                VirSchema virSchema = virSchemaDAO.find(mappingItem.getIntAttrName());
+                if (virSchema != null) {
+                    for (Any<?, ?> any : anys) {
+                        LOG.debug("Expire entry cache {}-{}", any.getKey(), mappingItem.getIntAttrName());
+                        virAttrCache.expire(any.getType().getKey(), any.getKey(), mappingItem.getIntAttrName());
+
+                        AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
+                        for (String value : virAttrHandler.getValues(any, virSchema)) {
+                            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                            attrValue.setStringValue(value);
+                            values.add(attrValue);
+                        }
+
+                        LOG.debug("Retrieved values for {}"
+                                + "\n* IntAttrName {}"
+                                + "\n* IntMappingType {}"
+                                + "\n* Attribute values {}",
+                                virSchema.getKey(), mappingItem.getIntAttrName(), mappingItem.getIntMappingType(),
+                                values);
+                    }
+                }
+                break;
+
             case UserKey:
             case GroupKey:
             case AnyObjectKey:
-                for (Any<?, ?, ?> any : anys) {
+                for (Any<?, ?> any : anys) {
                     AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
                     PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
                     attrValue.setStringValue(any.getKey().toString());
@@ -647,7 +581,7 @@ public class MappingUtils {
                 break;
 
             case Username:
-                for (Any<?, ?, ?> any : anys) {
+                for (Any<?, ?> any : anys) {
                     if (any instanceof User) {
                         UPlainAttrValue attrValue = entityFactory.newEntity(UPlainAttrValue.class);
                         attrValue.setStringValue(((User) any).getUsername());
@@ -657,7 +591,7 @@ public class MappingUtils {
                 break;
 
             case GroupName:
-                for (Any<?, ?, ?> any : anys) {
+                for (Any<?, ?> any : anys) {
                     if (any instanceof Group) {
                         GPlainAttrValue attrValue = entityFactory.newEntity(GPlainAttrValue.class);
                         attrValue.setStringValue(((Group) any).getName());
@@ -674,7 +608,7 @@ public class MappingUtils {
                         ? null
                         : provision.getMapping();
 
-                for (Any<?, ?, ?> any : anys) {
+                for (Any<?, ?> any : anys) {
                     if (any instanceof Group) {
                         Group group = (Group) any;
                         String groupOwnerValue = null;
@@ -720,9 +654,9 @@ public class MappingUtils {
      * @return connObjectKey internal value
      */
     @Transactional(readOnly = true)
-    public String getConnObjectKeyValue(final Any<?, ?, ?> any, final Provision provision) {
+    public String getConnObjectKeyValue(final Any<?, ?> any, final Provision provision) {
         List<PlainAttrValue> values = getIntValues(provision, provision.getMapping().getConnObjectKeyItem(),
-                Collections.<Any<?, ?, ?>>singletonList(any), null);
+                Collections.<Any<?, ?>>singletonList(any));
         return values == null || values.isEmpty()
                 ? null
                 : values.get(0).getValueAsString();

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/misc/src/main/java/org/apache/syncope/core/misc/jexl/JexlUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/jexl/JexlUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/jexl/JexlUtils.java
index 443bbae..3afe6e5 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/jexl/JexlUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/jexl/JexlUtils.java
@@ -35,8 +35,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.core.persistence.api.entity.DerAttr;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
-import org.apache.syncope.core.misc.DataFormat;
+import org.apache.syncope.core.misc.FormatUtils;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.slf4j.Logger;
@@ -126,7 +125,7 @@ public final class JexlUtils {
                         context.set(fieldName, fieldValue == null
                                 ? StringUtils.EMPTY
                                 : (type.equals(Date.class)
-                                        ? DataFormat.format((Date) fieldValue, false)
+                                        ? FormatUtils.format((Date) fieldValue, false)
                                         : fieldValue));
 
                         LOG.debug("Add field {} with value {}", fieldName, fieldValue);
@@ -140,7 +139,7 @@ public final class JexlUtils {
         }
 
         if (object instanceof Any) {
-            Any<?, ?, ?> any = (Any<?, ?, ?>) object;
+            Any<?, ?> any = (Any<?, ?>) object;
             if (any.getRealm() != null) {
                 context.set("realm", any.getRealm().getName());
             }
@@ -195,40 +194,16 @@ public final class JexlUtils {
         return context;
     }
 
-    public static JexlContext addVirAttrsToContext(final Collection<? extends VirAttr> virAttrs,
-            final JexlContext jexlContext) {
-
-        JexlContext context = jexlContext == null
-                ? new MapContext()
-                : jexlContext;
-
-        for (VirAttr<?> virAttr : virAttrs) {
-            if (virAttr.getSchema() != null) {
-                List<String> attrValues = virAttr.getValues();
-                String expressionValue = attrValues.isEmpty()
-                        ? StringUtils.EMPTY
-                        : attrValues.get(0);
-
-                LOG.debug("Add virtual attribute {} with value {}", virAttr.getSchema().getKey(), expressionValue);
-
-                context.set(virAttr.getSchema().getKey(), expressionValue);
-            }
-        }
-
-        return context;
-    }
-
-    public static boolean evaluateMandatoryCondition(final String mandatoryCondition, final Any<?, ?, ?> any) {
+    public static boolean evaluateMandatoryCondition(final String mandatoryCondition, final Any<?, ?> any) {
         JexlContext jexlContext = new MapContext();
         addPlainAttrsToContext(any.getPlainAttrs(), jexlContext);
         addDerAttrsToContext(any.getDerAttrs(), any.getPlainAttrs(), jexlContext);
-        addVirAttrsToContext(any.getVirAttrs(), jexlContext);
 
         return Boolean.parseBoolean(evaluate(mandatoryCondition, jexlContext));
     }
 
     public static String evaluate(final String expression,
-            final Any<?, ?, ?> any, final Collection<? extends PlainAttr<?>> attributes) {
+            final Any<?, ?> any, final Collection<? extends PlainAttr<?>> attributes) {
 
         JexlContext jexlContext = new MapContext();
         JexlUtils.addPlainAttrsToContext(attributes, jexlContext);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
index 86c97e3..bfda35f 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
@@ -25,7 +25,7 @@ import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 
-public interface AnyDAO<A extends Any<?, ?, ?>> extends DAO<A, Long> {
+public interface AnyDAO<A extends Any<?, ?>> extends DAO<A, Long> {
 
     A authFind(Long key);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
index f53dff6..00471e0 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnySearchDAO.java
@@ -25,7 +25,7 @@ import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.Any;
 
-public interface AnySearchDAO extends DAO<Any<?, ?, ?>, Long> {
+public interface AnySearchDAO extends DAO<Any<?, ?>, Long> {
 
     /**
      * @param adminRealms realms for which the caller owns the proper entitlement(s)
@@ -42,7 +42,7 @@ public interface AnySearchDAO extends DAO<Any<?, ?, ?>, Long> {
      * @param <T> any
      * @return the list of any objects matching the given search condition
      */
-    <T extends Any<?, ?, ?>> List<T> search(
+    <T extends Any<?, ?>> List<T> search(
             Set<String> adminRealms, SearchCond searchCondition, AnyTypeKind kind);
 
     /**
@@ -53,7 +53,7 @@ public interface AnySearchDAO extends DAO<Any<?, ?, ?>, Long> {
      * @param <T> any
      * @return the list of any objects matching the given search condition
      */
-    <T extends Any<?, ?, ?>> List<T> search(
+    <T extends Any<?, ?>> List<T> search(
             Set<String> adminRealms, SearchCond searchCondition, List<OrderByClause> orderBy, AnyTypeKind kind);
 
     /**
@@ -66,7 +66,7 @@ public interface AnySearchDAO extends DAO<Any<?, ?, ?>, Long> {
      * @param <T> any
      * @return the list of any objects matching the given search condition (in the given page)
      */
-    <T extends Any<?, ?, ?>> List<T> search(
+    <T extends Any<?, ?>> List<T> search(
             Set<String> adminRealms, SearchCond searchCondition, int page, int itemsPerPage,
             List<OrderByClause> orderBy, AnyTypeKind kind);
 
@@ -79,5 +79,5 @@ public interface AnySearchDAO extends DAO<Any<?, ?, ?>, Long> {
      * @param <T> any
      * @return true if any matches searchCondition
      */
-    <T extends Any<?, ?, ?>> boolean matches(T any, SearchCond searchCondition, AnyTypeKind kind);
+    <T extends Any<?, ?>> boolean matches(T any, SearchCond searchCondition, AnyTypeKind kind);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
index a72937c..aeabe23 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
@@ -21,13 +21,16 @@ package org.apache.syncope.core.persistence.api.dao;
 import java.util.List;
 import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.PolicyType;
-import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.Policy;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 
 public interface ExternalResourceDAO extends DAO<ExternalResource, String> {
 
     ExternalResource find(String key);
 
+    Provision findProvision(Long key);
+
     List<ExternalResource> findByPolicy(Policy policy);
 
     List<ExternalResource> findWithoutPolicy(PolicyType type);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/VirAttrDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/VirAttrDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/VirAttrDAO.java
deleted file mode 100644
index b62cb87..0000000
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/VirAttrDAO.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.persistence.api.dao;
-
-import java.util.List;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
-
-public interface VirAttrDAO extends DAO<VirAttr<?>, Long> {
-
-    <T extends VirAttr<?>> T find(Long key, Class<T> reference);
-
-    <T extends VirAttr<?>> List<T> findAll(Class<T> reference);
-
-    <T extends VirAttr<?>> T save(T virtualAttribute);
-
-    <T extends VirAttr<?>> void delete(Long key, Class<T> reference);
-
-    <T extends VirAttr<?>> void delete(T virAttr);
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/VirSchemaDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/VirSchemaDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/VirSchemaDAO.java
index 2bcd81c..9479428 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/VirSchemaDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/VirSchemaDAO.java
@@ -18,8 +18,12 @@
  */
 package org.apache.syncope.core.persistence.api.dao;
 
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.Attr;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 
-public interface VirSchemaDAO extends SchemaDAO<VirSchema, VirAttr<?>> {
+public interface VirSchemaDAO extends SchemaDAO<VirSchema, Attr<VirSchema, ?>> {
+
+    List<VirSchema> findByProvision(Provision provision);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
index 0384db7..f56485e 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
@@ -22,7 +22,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import java.util.List;
 import java.util.Set;
 
-public interface Any<P extends PlainAttr<?>, D extends DerAttr<?>, V extends VirAttr<?>> extends AnnotatedEntity<Long> {
+public interface Any<P extends PlainAttr<?>, D extends DerAttr<?>> extends AnnotatedEntity<Long> {
 
     AnyType getType();
 
@@ -56,14 +56,6 @@ public interface Any<P extends PlainAttr<?>, D extends DerAttr<?>, V extends Vir
 
     List<? extends D> getDerAttrs();
 
-    boolean add(V virAttr);
-
-    boolean remove(V virAttr);
-
-    V getVirAttr(String virSchemaName);
-
-    List<? extends V> getVirAttrs();
-
     boolean add(ExternalResource resource);
 
     boolean remove(ExternalResource resource);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
index 8c64086..702e7a6 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
@@ -26,7 +26,7 @@ public interface AnyUtils {
 
     AnyTypeKind getAnyTypeKind();
 
-    <T extends Any<?, ?, ?>> Class<T> anyClass();
+    <T extends Any<?, ?>> Class<T> anyClass();
 
     <T extends PlainAttr<?>> Class<T> plainAttrClass();
 
@@ -44,10 +44,6 @@ public interface AnyUtils {
 
     <T extends DerAttr<?>> T newDerAttr();
 
-    <T extends VirAttr<?>> Class<T> virAttrClass();
-
-    <T extends VirAttr<?>> T newVirAttr();
-
     IntMappingType plainIntMappingType();
 
     IntMappingType derIntMappingType();

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtilsFactory.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtilsFactory.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtilsFactory.java
index 2e2a49e..d64e7e1 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtilsFactory.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtilsFactory.java
@@ -26,5 +26,5 @@ public interface AnyUtilsFactory {
 
     AnyUtils getInstance(String anyTypeKind);
 
-    AnyUtils getInstance(Any<?, ?, ?> any);
+    AnyUtils getInstance(Any<?, ?> any);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Attr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Attr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Attr.java
index 2be01e9..500b835 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Attr.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Attr.java
@@ -18,7 +18,7 @@
  */
 package org.apache.syncope.core.persistence.api.entity;
 
-public interface Attr<S extends Schema, O extends Any<?, ?, ?>> extends Entity<Long> {
+public interface Attr<S extends Schema, O extends Any<?, ?>> extends Entity<Long> {
 
     O getOwner();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DerAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DerAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DerAttr.java
index 9eb3b7a..ff15a4a 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DerAttr.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DerAttr.java
@@ -20,7 +20,7 @@ package org.apache.syncope.core.persistence.api.entity;
 
 import java.util.Collection;
 
-public interface DerAttr<O extends Any<?, ?, ?>> extends Attr<DerSchema, O> {
+public interface DerAttr<O extends Any<?, ?>> extends Attr<DerSchema, O> {
 
     String getValue(Collection<? extends PlainAttr<?>> attrs);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynGroupMembership.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynGroupMembership.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynGroupMembership.java
index b01fe70..ebb7cf8 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynGroupMembership.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynGroupMembership.java
@@ -20,7 +20,7 @@ package org.apache.syncope.core.persistence.api.entity;
 
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 
-public interface DynGroupMembership<A extends Any<?, ?, ?>> extends DynMembership<A> {
+public interface DynGroupMembership<A extends Any<?, ?>> extends DynMembership<A> {
 
     Group getGroup();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynMembership.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynMembership.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynMembership.java
index ba0a62f..24c6309 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynMembership.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/DynMembership.java
@@ -20,7 +20,7 @@ package org.apache.syncope.core.persistence.api.entity;
 
 import java.util.List;
 
-public interface DynMembership<A extends Any<?, ?, ?>> extends Entity<Long> {
+public interface DynMembership<A extends Any<?, ?>> extends Entity<Long> {
 
     String getFIQLCond();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Membership.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Membership.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Membership.java
index 55ac640..9d1466c 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Membership.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Membership.java
@@ -20,7 +20,7 @@ package org.apache.syncope.core.persistence.api.entity;
 
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 
-public interface Membership<L extends Any<?, ?, ?>> extends Relationship<L, Group> {
+public interface Membership<L extends Any<?, ?>> extends Relationship<L, Group> {
 
     @Override
     MembershipType getType();

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
index b149851..8d8a7c1 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
@@ -20,7 +20,7 @@ package org.apache.syncope.core.persistence.api.entity;
 
 import java.util.List;
 
-public interface PlainAttr<O extends Any<?, ?, ?>> extends Attr<PlainSchema, O> {
+public interface PlainAttr<O extends Any<?, ?>> extends Attr<PlainSchema, O> {
 
     void add(String value, AnyUtils anyUtils);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Relationship.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Relationship.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Relationship.java
index 0549714..b87563e 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Relationship.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Relationship.java
@@ -18,7 +18,7 @@
  */
 package org.apache.syncope.core.persistence.api.entity;
 
-public interface Relationship<L extends Any<?, ?, ?>, R extends Any<?, ?, ?>> extends Entity<Long> {
+public interface Relationship<L extends Any<?, ?>, R extends Any<?, ?>> extends Entity<Long> {
 
     RelationshipType getType();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/VirAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/VirAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/VirAttr.java
deleted file mode 100644
index 7761d93..0000000
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/VirAttr.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.persistence.api.entity;
-
-import java.util.List;
-
-public interface VirAttr<O extends Any<?, ?, ?>> extends Attr<VirSchema, O> {
-
-    List<String> getValues();
-
-    boolean add(String value);
-
-    boolean remove(String value);
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/VirSchema.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/VirSchema.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/VirSchema.java
index 8b796c4..65cc11d 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/VirSchema.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/VirSchema.java
@@ -18,7 +18,20 @@
  */
 package org.apache.syncope.core.persistence.api.entity;
 
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+
 public interface VirSchema extends Schema {
 
     void setReadonly(boolean readonly);
+
+    Provision getProvision();
+
+    void setProvision(Provision provision);
+
+    String getExtAttrName();
+
+    void setExtAttrName(String extAttrName);
+
+    MappingItem asLinkingMappingItem();
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AVirAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AVirAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AVirAttr.java
deleted file mode 100644
index be86c59..0000000
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AVirAttr.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.persistence.api.entity.anyobject;
-
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
-
-public interface AVirAttr extends VirAttr<AnyObject> {
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
index 2094269..1e10257 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
@@ -23,7 +23,7 @@ import java.util.List;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 
-public interface AnyObject extends Any<APlainAttr, ADerAttr, AVirAttr> {
+public interface AnyObject extends Any<APlainAttr, ADerAttr> {
 
     boolean add(ARelationship relationship);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/conf/Conf.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/conf/Conf.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/conf/Conf.java
index 2b6e424..f4ca14d 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/conf/Conf.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/conf/Conf.java
@@ -21,9 +21,8 @@ package org.apache.syncope.core.persistence.api.entity.conf;
 import java.util.List;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.DerAttr;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
 
-public interface Conf extends Any<CPlainAttr, DerAttr<?>, VirAttr<?>> {
+public interface Conf extends Any<CPlainAttr, DerAttr<?>> {
 
     void setKey(Long key);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/GVirAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/GVirAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/GVirAttr.java
deleted file mode 100644
index 1847794..0000000
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/GVirAttr.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.persistence.api.entity.group;
-
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
-
-public interface GVirAttr extends VirAttr<Group> {
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/Group.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/Group.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/Group.java
index cb6008e..0afddba 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/Group.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/group/Group.java
@@ -25,7 +25,7 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembers
 import org.apache.syncope.core.persistence.api.entity.user.UDynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 
-public interface Group extends Any<GPlainAttr, GDerAttr, GVirAttr> {
+public interface Group extends Any<GPlainAttr, GDerAttr> {
 
     String getName();
 
@@ -63,18 +63,6 @@ public interface Group extends Any<GPlainAttr, GDerAttr, GVirAttr> {
     @Override
     List<? extends GDerAttr> getDerAttrs();
 
-    @Override
-    boolean add(GVirAttr attr);
-
-    @Override
-    boolean remove(GVirAttr virAttr);
-
-    @Override
-    GVirAttr getVirAttr(String virSchemaName);
-
-    @Override
-    List<? extends GVirAttr> getVirAttrs();
-
     ADynGroupMembership getADynMembership();
 
     void setADynMembership(ADynGroupMembership aDynMembership);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/PropagationTask.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/PropagationTask.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/PropagationTask.java
index db9e5a3..2d19436 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/PropagationTask.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/PropagationTask.java
@@ -54,6 +54,10 @@ public interface PropagationTask extends Task {
 
     void setAnyTypeKind(AnyTypeKind anyTypeKind);
 
+    String getAnyType();
+
+    void setAnyType(String anyType);
+
     ExternalResource getResource();
 
     void setResource(ExternalResource resource);