You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2015/10/22 14:26:59 UTC

[05/10] syncope git commit: [SYNCOPE-709] Refactoring completed

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