Author: ilgrosso
Date: Mon Dec 24 09:56:52 2012
New Revision: 1425615

URL: http://svn.apache.org/viewvc?rev=1425615&view=rev
Log:
[SYNCOPE-26] Added sample (but working) LDAPMembershipSyncActions

Added:
    
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/LDAPMembershipSyncActions.java
   (with props)
Modified:
    
syncope/trunk/archetype/src/main/resources/archetype-resources/core/src/test/resources/content.xml
    syncope/trunk/build-tools/src/main/resources/content.ldif
    
syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/SyncActions.java
    
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/ConnectorFacadeProxy.java
    
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/LDAPMembershipPropagationActions.java
    
syncope/trunk/core/src/main/java/org/apache/syncope/core/quartz/SampleJob.java
    
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/DefaultSyncActions.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncJob.java
    
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncopeSyncResultHandler.java
    
syncope/trunk/core/src/main/java/org/apache/syncope/core/workflow/user/activiti/SyncopeUserQueryImpl.java
    
syncope/trunk/core/src/test/java/org/apache/syncope/core/quartz/TestSyncActions.java
    
syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/TaskTestITCase.java
    syncope/trunk/core/src/test/resources/content.xml

Modified: 
syncope/trunk/archetype/src/main/resources/archetype-resources/core/src/test/resources/content.xml
URL: 
http://svn.apache.org/viewvc/syncope/trunk/archetype/src/main/resources/archetype-resources/core/src/test/resources/content.xml?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- 
syncope/trunk/archetype/src/main/resources/archetype-resources/core/src/test/resources/content.xml
 (original)
+++ 
syncope/trunk/archetype/src/main/resources/archetype-resources/core/src/test/resources/content.xml
 Mon Dec 24 09:56:52 2012
@@ -542,7 +542,7 @@ under the License.
   <UMapping id="11" resource_name="resource-ldap"
             accountlink="&apos;uid=&apos; + username + 
&apos;,ou=people,o=isp&apos;"/>
   <UMappingItem id="311" accountid="1" password="0" mapping_id="11"
-                extAttrName="__NAME__" intAttrName="Username" 
intMappingType="Username"
+                extAttrName="__UID__" intAttrName="Username" 
intMappingType="Username"
                 mandatoryCondition="true"/>
   <UMappingItem id="312" accountid="0" password="1" mapping_id="11"
                 extAttrName="__PASSWORD__" intAttrName="Password" 
intMappingType="Password"
@@ -551,7 +551,7 @@ under the License.
                 extAttrName="sn" intAttrName="surname" 
intMappingType="UserSchema"
                 mandatoryCondition="true"/>
   <UMappingItem id="314" accountid="0" password="0" mapping_id="11"
-                extAttrName="cn" intAttrName="firstname" 
intMappingType="UserSchema"
+                extAttrName="cn" intAttrName="fullname" 
intMappingType="UserSchema"
                 mandatoryCondition="true"/>
   <UMappingItem id="315" accountid="0" password="0" mapping_id="11"
                 extAttrName="mail" intAttrName="email" 
intMappingType="UserSchema"
@@ -562,6 +562,9 @@ under the License.
   <UMappingItem id="317" accountid="0" password="0" mapping_id="11"
                 extAttrName="postalAddress" intAttrName="postalAddress" 
intMappingType="MembershipSchema"
                 mandatoryCondition="false"/>
+  <UMappingItem id="318" accountid="0" password="0" mapping_id="11"
+                extAttrName="mail" intAttrName="userId" 
intMappingType="UserSchema"
+                mandatoryCondition="false"/>
   <RMapping id="1" resource_name="resource-ldap"
             accountlink="&apos;cn=&apos; + name + 
&apos;,ou=groups,o=isp&apos;"/>
   <RMappingItem id="1" accountid="1" password="0" mapping_id="1"
@@ -626,8 +629,9 @@ under the License.
         fullReconciliation="1" performCreate="1" performDelete="1" 
performUpdate="1" syncStatus="0"
         jobClassName="org.apache.syncope.core.sync.SyncJob"/>
   <Task DTYPE="SyncTask" id="11" name="LDAP Sync Task" 
resource_name="resource-ldap"
-          fullReconciliation="1" performCreate="1" performDelete="1" 
performUpdate="1" syncStatus="0"
-          jobClassName="org.apache.syncope.core.sync.SyncJob"/>
+        fullReconciliation="1" performCreate="1" performDelete="1" 
performUpdate="1" syncStatus="0"
+        
actionsClassName="org.apache.syncope.core.sync.LDAPMembershipSyncActions"  
+        jobClassName="org.apache.syncope.core.sync.SyncJob"/>
         
   <NotificationTask_recipients notificationtask_id="8" 
address="recipi...@prova.org"/>
 

Modified: syncope/trunk/build-tools/src/main/resources/content.ldif
URL: 
http://svn.apache.org/viewvc/syncope/trunk/build-tools/src/main/resources/content.ldif?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- syncope/trunk/build-tools/src/main/resources/content.ldif (original)
+++ syncope/trunk/build-tools/src/main/resources/content.ldif Mon Dec 24 
09:56:52 2012
@@ -29,3 +29,16 @@ objectClass: groupOfUniqueNames
 objectClass: top
 cn: testLDAPGroup
 uniqueMember: uid=admin,ou=system
+uniqueMember: uid=syncFromLDAP,ou=People,o=isp
+
+DN: uid=syncFromLDAP,ou=People,o=isp
+objectClass: organizationalPerson
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: top
+cn: Sync from LDAP
+description: Active
+mail: syncfroml...@syncope.apache.org
+sn: Surname
+uid: syncFromLDAP
+userpassword:: cGFzc3dvcmQxMjM=

Modified: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/SyncActions.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/SyncActions.java?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- 
syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/SyncActions.java
 (original)
+++ 
syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/SyncActions.java
 Mon Dec 24 09:56:52 2012
@@ -21,6 +21,7 @@ package org.apache.syncope.core.persiste
 import java.util.List;
 import org.apache.syncope.client.mod.AbstractAttributableMod;
 import org.apache.syncope.client.to.AbstractAttributableTO;
+import org.apache.syncope.core.sync.SyncopeSyncResultHandler;
 import org.identityconnectors.framework.common.objects.SyncDelta;
 import org.quartz.JobExecutionException;
 
@@ -32,62 +33,67 @@ public interface SyncActions {
     /**
      * Action to be executed before to start the synchronization task 
execution.
      *
-     * @param task synchronization task to be executed.
+     * @param handler synchronization handler being executed.
      * @throws JobExecutionException in case of generic failure.
      */
-    void beforeAll(final SyncTask task) throws JobExecutionException;
+    void beforeAll(final SyncopeSyncResultHandler handler) throws 
JobExecutionException;
 
     /**
      * Action to be executed before to create a synchronized user locally.
      *
+     * @param handler synchronization handler being executed.
      * @param delta retrieved synchronization information
      * @param subject user / role to be created
      * @return synchronization information used for user status evaluation and 
to be passed to the 'after' method.
      * @throws JobExecutionException in case of generic failure
      */
-    <T extends AbstractAttributableTO> SyncDelta beforeCreate(final SyncDelta 
delta, final T subject)
-            throws JobExecutionException;
+    <T extends AbstractAttributableTO> SyncDelta beforeCreate(final 
SyncopeSyncResultHandler handler,
+            final SyncDelta delta, final T subject) throws 
JobExecutionException;
 
     /**
      * Action to be executed before to update a synchronized user locally.
      *
+     * @param handler synchronization handler being executed.
      * @param delta retrieved synchronization information
      * @param subject local user / role information
      * @param subjectMod modification
      * @return synchronization information used for logging and to be passed 
to the 'after' method.
      * @throws JobExecutionException in case of generic failure.
      */
-    <T extends AbstractAttributableTO, K extends AbstractAttributableMod> 
SyncDelta beforeUpdate(final SyncDelta delta,
-            final T subject, final K subjectMod) throws JobExecutionException;
+    <T extends AbstractAttributableTO, K extends AbstractAttributableMod> 
SyncDelta beforeUpdate(
+            final SyncopeSyncResultHandler handler, final SyncDelta delta, 
final T subject, final K subjectMod)
+            throws JobExecutionException;
 
     /**
      * Action to be executed before to delete a synchronized user locally.
      *
+     * @param handler synchronization handler being executed.
      * @param delta retrieved synchronization information
      * @param subject lcao user / role to be deleted
      * @return synchronization information used for logging and to be passed 
to the 'after' method.
      * @throws JobExecutionException in case of generic failure
      */
-    <T extends AbstractAttributableTO> SyncDelta beforeDelete(final SyncDelta 
delta, final T subject)
-            throws JobExecutionException;
+    <T extends AbstractAttributableTO> SyncDelta beforeDelete(final 
SyncopeSyncResultHandler handler,
+            final SyncDelta delta, final T subject) throws 
JobExecutionException;
 
     /**
      * Action to be executed after each local user synchronization.
      *
+     * @param handler synchronization handler being executed.
      * @param delta retrieved synchronization information (may be modified by 
'beforeCreate/beforeUpdate/beforeDelete')
      * @param subject synchronized local user / role
      * @param result global synchronization results at the current 
synchronization step
      * @throws JobExecutionException in case of generic failure
      */
-    <T extends AbstractAttributableTO> void after(final SyncDelta delta, final 
T subject, final SyncResult result)
-            throws JobExecutionException;
+    <T extends AbstractAttributableTO> void after(final 
SyncopeSyncResultHandler handler, final SyncDelta delta,
+            final T subject, final SyncResult result) throws 
JobExecutionException;
 
     /**
      * Action to be executed after the synchronization task completion.
      *
-     * @param task executed synchronization task
+     * @param handler synchronization handler being executed.
      * @param results synchronization result
      * @throws JobExecutionException in case of generic failure
      */
-    void afterAll(final SyncTask task, final List<SyncResult> results) throws 
JobExecutionException;
+    void afterAll(final SyncopeSyncResultHandler handler, final 
List<SyncResult> results) throws JobExecutionException;
 }

Modified: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/ConnectorFacadeProxy.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/ConnectorFacadeProxy.java?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- 
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/ConnectorFacadeProxy.java
 (original)
+++ 
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/ConnectorFacadeProxy.java
 Mon Dec 24 09:56:52 2012
@@ -20,6 +20,7 @@ package org.apache.syncope.core.propagat
 
 import java.io.File;
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -57,6 +58,7 @@ import org.identityconnectors.framework.
 import org.identityconnectors.framework.common.objects.SyncResultsHandler;
 import org.identityconnectors.framework.common.objects.SyncToken;
 import org.identityconnectors.framework.common.objects.Uid;
+import org.identityconnectors.framework.common.objects.filter.Filter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.util.ClassUtils;
@@ -352,6 +354,27 @@ public class ConnectorFacadeProxy {
         return result;
     }
 
+    public List<ConnectorObject> search(final ObjectClass objectClass, final 
Filter filter,
+            final OperationOptions options) {
+
+        final List<ConnectorObject> result = new ArrayList<ConnectorObject>();
+
+        if 
(activeConnInstance.getCapabilities().contains(ConnectorCapability.SEARCH)) {
+            connector.search(objectClass, filter, new ResultsHandler() {
+
+                @Override
+                public boolean handle(final ConnectorObject obj) {
+                    return result.add(obj);
+                }
+            }, options);
+        } else {
+            LOG.info("Search was attempted, although the connector only has 
these capabilities: {}. No action.",
+                    activeConnInstance.getCapabilities());
+        }
+
+        return result;
+    }
+
     /**
      * Get remote object used by the propagation manager in order to choose 
for a create (object doesn't exist) or an
      * update (object exists).

Modified: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/LDAPMembershipPropagationActions.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/LDAPMembershipPropagationActions.java?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- 
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/LDAPMembershipPropagationActions.java
 (original)
+++ 
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/LDAPMembershipPropagationActions.java
 Mon Dec 24 09:56:52 2012
@@ -43,21 +43,27 @@ import org.springframework.transaction.a
 /**
  * Simple action for propagating role memberships to LDAP groups, when the 
same resource is configured for both users
  * and roles.
+ * 
+ * @see org.apache.syncope.core.sync.LDAPMembershipSyncActions
  */
 public class LDAPMembershipPropagationActions extends 
DefaultPropagationActions {
 
-    private static final Logger LOG = 
LoggerFactory.getLogger(LDAPMembershipPropagationActions.class);
-
-    /**
-     * Allows easy subclassing for the ConnId AD connector bundle.
-     */
-    protected static final String GROUP_MEMBERSHIP_ATTR = "ldapGroups";
+    protected static final Logger LOG = 
LoggerFactory.getLogger(LDAPMembershipPropagationActions.class);
 
     @Autowired
-    private UserDAO userDAO;
+    protected UserDAO userDAO;
 
     @Autowired
-    private JexlUtil jexlUtil;
+    protected JexlUtil jexlUtil;
+
+    /**
+     * Allows easy subclassing for the ConnId AD connector bundle.
+     *
+     * @return the name of the attribute used to keep track of group 
memberships
+     */
+    protected String getGroupMembershipAttrName() {
+        return "ldapGroups";
+    }
 
     @Transactional(readOnly = true)
     @Override
@@ -95,7 +101,7 @@ public class LDAPMembershipPropagationAc
 
             if (!roleAccountLinks.isEmpty()) {
                 Set<Attribute> attributes = new 
HashSet<Attribute>(task.getAttributes());
-                attributes.add(AttributeBuilder.build(GROUP_MEMBERSHIP_ATTR, 
roleAccountLinks));
+                
attributes.add(AttributeBuilder.build(getGroupMembershipAttrName(), 
roleAccountLinks));
                 task.setAttributes(attributes);
             }
         } else {

Modified: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/quartz/SampleJob.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/quartz/SampleJob.java?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- 
syncope/trunk/core/src/main/java/org/apache/syncope/core/quartz/SampleJob.java 
(original)
+++ 
syncope/trunk/core/src/main/java/org/apache/syncope/core/quartz/SampleJob.java 
Mon Dec 24 09:56:52 2012
@@ -18,9 +18,9 @@
  */
 package org.apache.syncope.core.quartz;
 
-import org.quartz.JobExecutionException;
 import org.apache.syncope.core.persistence.beans.SchedTask;
 import org.apache.syncope.core.persistence.beans.TaskExec;
+import org.quartz.JobExecutionException;
 
 /**
  * Sample implementation for execution a scheduled task.

Modified: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/DefaultSyncActions.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/DefaultSyncActions.java?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/DefaultSyncActions.java
 (original)
+++ 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/DefaultSyncActions.java
 Mon Dec 24 09:56:52 2012
@@ -23,7 +23,6 @@ import org.apache.syncope.client.mod.Abs
 import org.apache.syncope.client.to.AbstractAttributableTO;
 import org.apache.syncope.core.persistence.beans.SyncActions;
 import org.apache.syncope.core.persistence.beans.SyncResult;
-import org.apache.syncope.core.persistence.beans.SyncTask;
 import org.identityconnectors.framework.common.objects.SyncDelta;
 import org.quartz.JobExecutionException;
 
@@ -33,36 +32,38 @@ import org.quartz.JobExecutionException;
 public class DefaultSyncActions implements SyncActions {
 
     @Override
-    public void beforeAll(final SyncTask task) throws JobExecutionException {
+    public void beforeAll(final SyncopeSyncResultHandler handler) throws 
JobExecutionException {
     }
 
     @Override
-    public <T extends AbstractAttributableTO> SyncDelta beforeCreate(final 
SyncDelta delta, final T subject)
-            throws JobExecutionException {
+    public <T extends AbstractAttributableTO> SyncDelta beforeCreate(final 
SyncopeSyncResultHandler handler,
+            final SyncDelta delta, final T subject) throws 
JobExecutionException {
 
         return delta;
     }
 
     @Override
     public <T extends AbstractAttributableTO, K extends 
AbstractAttributableMod> SyncDelta beforeUpdate(
-            final SyncDelta delta, final T subject, final K subjectMod) throws 
JobExecutionException {
+            final SyncopeSyncResultHandler handler, final SyncDelta delta, 
final T subject, final K subjectMod)
+            throws JobExecutionException {
 
         return delta;
     }
 
     @Override
-    public <T extends AbstractAttributableTO> SyncDelta beforeDelete(final 
SyncDelta delta, final T subject)
-            throws JobExecutionException {
+    public <T extends AbstractAttributableTO> SyncDelta beforeDelete(
+            final SyncopeSyncResultHandler handler, final SyncDelta delta, 
final T subject) throws JobExecutionException {
 
         return delta;
     }
 
     @Override
-    public <T extends AbstractAttributableTO> void after(final SyncDelta 
delta, final T subject,
-            final SyncResult result) throws JobExecutionException {
+    public <T extends AbstractAttributableTO> void after(final 
SyncopeSyncResultHandler handler,
+            final SyncDelta delta, final T subject, final SyncResult result) 
throws JobExecutionException {
     }
 
     @Override
-    public void afterAll(final SyncTask task, final List<SyncResult> results) 
throws JobExecutionException {
+    public void afterAll(final SyncopeSyncResultHandler handler, final 
List<SyncResult> results)
+            throws JobExecutionException {
     }
 }

Added: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/LDAPMembershipSyncActions.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/LDAPMembershipSyncActions.java?rev=1425615&view=auto
==============================================================================
--- 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/LDAPMembershipSyncActions.java
 (added)
+++ 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/LDAPMembershipSyncActions.java
 Mon Dec 24 09:56:52 2012
@@ -0,0 +1,282 @@
+/*
+ * 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.sync;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.syncope.client.mod.AbstractAttributableMod;
+import org.apache.syncope.client.mod.MembershipMod;
+import org.apache.syncope.client.mod.UserMod;
+import org.apache.syncope.client.to.AbstractAttributableTO;
+import org.apache.syncope.client.to.RoleTO;
+import org.apache.syncope.core.notification.NotificationManager;
+import org.apache.syncope.core.persistence.beans.ExternalResource;
+import org.apache.syncope.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.persistence.beans.SyncResult;
+import org.apache.syncope.core.persistence.beans.SyncTask;
+import org.apache.syncope.core.persistence.beans.membership.Membership;
+import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
+import org.apache.syncope.core.persistence.dao.RoleDAO;
+import org.apache.syncope.core.propagation.ConnectorFacadeProxy;
+import org.apache.syncope.core.propagation.ConnectorFactory;
+import org.apache.syncope.core.propagation.PropagationException;
+import org.apache.syncope.core.propagation.PropagationManager;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.util.AttributableUtil;
+import org.apache.syncope.core.workflow.WorkflowResult;
+import org.apache.syncope.core.workflow.user.UserWorkflowAdapter;
+import org.apache.syncope.types.AttributableType;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.Name;
+import org.identityconnectors.framework.common.objects.ObjectClass;
+import org.identityconnectors.framework.common.objects.OperationOptionsBuilder;
+import org.identityconnectors.framework.common.objects.SyncDelta;
+import org.identityconnectors.framework.common.objects.filter.EqualsFilter;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Simple action for synchronizing LDAP groups memberships to Syncope role 
memberships, when the same resource is
+ * configured for both users and roles.
+ *
+ * @see org.apache.syncope.core.propagation.LDAPMembershipPropagationActions
+ */
+public class LDAPMembershipSyncActions extends DefaultSyncActions {
+
+    protected static final Logger LOG = 
LoggerFactory.getLogger(LDAPMembershipSyncActions.class);
+
+    @Autowired
+    protected RoleDAO roleDAO;
+
+    @Autowired
+    protected ConnectorFactory connInstanceLoader;
+
+    @Autowired
+    protected UserWorkflowAdapter uwfAdapter;
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    private PropagationTaskExecutor taskExecutor;
+
+    @Autowired
+    private NotificationManager notificationManager;
+
+    protected Map<Long, Long> membersBeforeRoleUpdate = Collections.<Long, 
Long>emptyMap();
+
+    /**
+     * Allows easy subclassing for the ConnId AD connector bundle.
+     *
+     * @return the name of the attribute used to keep track of group 
memberships
+     */
+    protected String getGroupMembershipAttrName() {
+        return "uniquemember";
+    }
+
+    /**
+     * Keep track of members of the role being updated <b>before</b> actual 
update takes place. This is not needed on
+     * <ul> <li>beforeCreate() - because the synchronizing role does not exist 
yet on Syncope</li> <li>beforeDelete() -
+     * because role delete cascades as membership removal for all users 
involved</li> </ul>
+     */
+    @Transactional(readOnly = true)
+    @Override
+    public <T extends AbstractAttributableTO, K extends 
AbstractAttributableMod> SyncDelta beforeUpdate(
+            final SyncopeSyncResultHandler handler, final SyncDelta delta, 
final T subject, final K subjectMod)
+            throws JobExecutionException {
+
+        if (subject instanceof RoleTO) {
+            // search for all users assigned to given role
+            SyncopeRole role = roleDAO.find(subject.getId());
+            if (role != null) {
+                List<Membership> membs = roleDAO.findMemberships(role);
+                // save memberships before role update takes place
+                membersBeforeRoleUpdate = new HashMap<Long, 
Long>(membs.size());
+                for (Membership memb : membs) {
+                    membersBeforeRoleUpdate.put(memb.getSyncopeUser().getId(), 
memb.getId());
+                }
+            }
+        }
+
+        return super.beforeUpdate(handler, delta, subject, subjectMod);
+    }
+
+    /**
+     * Build UserMod for adding membership to given user, for given role.
+     *
+     * @param userId user to be assigned membership to given role
+     * @param roleTO role for adding membership
+     * @return UserMod for user update
+     */
+    protected UserMod getUserMod(final Long userId, final RoleTO roleTO) {
+        UserMod userMod = new UserMod();
+        // no actual modification takes place when user has already the role 
assigned
+        if (membersBeforeRoleUpdate.containsKey(userId)) {
+            membersBeforeRoleUpdate.remove(userId);
+        } else {
+            userMod.setId(userId);
+
+            MembershipMod membershipMod = new MembershipMod();
+            membershipMod.setRole(roleTO.getId());
+            userMod.addMembershipToBeAdded(membershipMod);
+        }
+
+        return userMod;
+    }
+
+    /**
+     * Read values of attribute returned by getGroupMembershipAttrName(); if 
not present in the given delta, perform an
+     * additioanl read on the underlying connector.
+     *
+     * @param delta representing the synchronizing role
+     * @param connector associated to the current resource
+     * @return value of attribute returned by getGroupMembershipAttrName()
+     * @see getGroupMembershipAttrName()
+     */
+    protected List<Object> getMembAttrValues(final SyncDelta delta, final 
ConnectorFacadeProxy connector) {
+        List<Object> result = Collections.<Object>emptyList();
+
+        // first, try to read the configured attribute from delta, returned by 
the ongoing synchronization
+        Attribute membAttr = 
delta.getObject().getAttributeByName(getGroupMembershipAttrName());
+        // if not found, perform an additional read on the underlying 
connector for the same connector object
+        if (membAttr == null) {
+            final OperationOptionsBuilder oob = new OperationOptionsBuilder();
+            oob.setAttributesToGet(getGroupMembershipAttrName());
+            membAttr = connector.getObjectAttribute(
+                    ObjectClass.GROUP, delta.getUid(), oob.build(), 
getGroupMembershipAttrName());
+        }
+        if (membAttr != null && membAttr.getValue() != null) {
+            result = membAttr.getValue();
+        }
+
+        return result;
+    }
+
+    /**
+     * Perform actual modifications (i.e. membership add / remove) for the 
given role on the given resource.
+     *
+     * @param userMod modifications to perform on the user
+     * @param resourceName resource to be propagated for changes
+     */
+    protected void userUpdate(final UserMod userMod, final String 
resourceName) {
+        if (userMod.getId() == 0) {
+            return;
+        }
+
+        try {
+            WorkflowResult<Map.Entry<Long, Boolean>> updated = 
uwfAdapter.update(userMod);
+
+            List<PropagationTask> tasks = 
propagationManager.getUserUpdateTaskIds(updated,
+                    userMod.getPassword(), 
userMod.getVirtualAttributesToBeRemoved(),
+                    userMod.getVirtualAttributesToBeUpdated(),
+                    Collections.singleton(resourceName));
+
+            taskExecutor.execute(tasks);
+
+            notificationManager.createTasks(updated.getResult().getKey(), 
updated.getPerformedTasks());
+        } catch (PropagationException e) {
+            LOG.error("Could not propagate {}", userMod, e);
+        } catch (Exception e) {
+            LOG.error("Could not perform update {}", userMod, e);
+        }
+    }
+
+    /**
+     * Synchronize Syncope memberships with the situation read on the external 
resource's group.
+     *
+     * @param handler syncope sync result handler
+     * @param delta representing the synchronizing role
+     * @param roleTO role after modification performed by the handler
+     * @throws JobExecutionException if anything goes wrong
+     */
+    protected void synchronizeMemberships(final SyncopeSyncResultHandler 
handler, final SyncDelta delta,
+            final RoleTO roleTO) throws JobExecutionException {
+
+        final SyncTask task = handler.getSyncTask();
+        final ExternalResource resource = task.getResource();
+
+        ConnectorFacadeProxy connector;
+        try {
+            connector = connInstanceLoader.getConnector(resource);
+        } catch (Exception e) {
+            final String msg = String.format("Connector instance bean for 
resource %s and connInstance %s not found",
+                    resource, resource.getConnector());
+
+            throw new JobExecutionException(msg, e);
+        }
+
+        for (Object membValue : getMembAttrValues(delta, connector)) {
+
+            final List<ConnectorObject> found = 
connector.search(ObjectClass.ACCOUNT,
+                    new EqualsFilter(new Name(membValue.toString())),
+                    
connector.getOperationOptions(resource.getUmapping().getItems()));
+
+            if (found.isEmpty()) {
+                LOG.debug("No account found on {} with __NAME__ {}", resource, 
membValue.toString());
+            } else {
+                if (found.size() > 1) {
+                    LOG.warn("More than one account found on {} with __NAME__ 
{} - taking first only",
+                            resource, membValue.toString());
+                }
+
+                ConnectorObject externalAccount = found.iterator().next();
+                final List<Long> userIds = 
handler.findExisting(externalAccount.getUid().getUidValue(),
+                        externalAccount, 
AttributableUtil.getInstance(AttributableType.USER));
+                if (userIds.isEmpty()) {
+                    LOG.debug("No matching user found for {}, aborting", 
externalAccount);
+                } else {
+                    if (userIds.size() > 1) {
+                        LOG.warn("More than one user found {} - taking first 
only", userIds);
+                    }
+
+                    UserMod userMod = getUserMod(userIds.iterator().next(), 
roleTO);
+                    userUpdate(userMod, resource.getName());
+                }
+            }
+        }
+
+        // finally remove any residual membership that was present before role 
update but not any more
+        for (Map.Entry<Long, Long> member : 
membersBeforeRoleUpdate.entrySet()) {
+            UserMod userMod = new UserMod();
+            userMod.setId(member.getKey());
+            userMod.addMembershipToBeRemoved(member.getValue());
+            userUpdate(userMod, resource.getName());
+        }
+    }
+
+    /**
+     * Synchronize membership at role synchronization time (because SyncJob 
first synchronize users then roles).
+     */
+    @Override
+    public <T extends AbstractAttributableTO> void after(final 
SyncopeSyncResultHandler handler, final SyncDelta delta,
+            final T subject, final SyncResult result) throws 
JobExecutionException {
+
+        if (!(subject instanceof RoleTO) || 
handler.getSyncTask().getResource().getUmapping() == null) {
+            super.after(handler, delta, subject, result);
+        } else {
+            synchronizeMemberships(handler, delta, (RoleTO) subject);
+        }
+    }
+}

Propchange: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/LDAPMembershipSyncActions.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/LDAPMembershipSyncActions.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/LDAPMembershipSyncActions.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncJob.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncJob.java?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncJob.java 
(original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncJob.java 
Mon Dec 24 09:56:52 2012
@@ -355,7 +355,7 @@ public class SyncJob extends AbstractTas
         handler.setResults(results);
         handler.setSyncTask(syncTask);
 
-        actions.beforeAll(syncTask);
+        actions.beforeAll(handler);
         try {
             if (syncTask.isFullReconciliation()) {
                 if (uMapping != null) {
@@ -390,7 +390,7 @@ public class SyncJob extends AbstractTas
         } catch (Exception e) {
             throw new JobExecutionException("While syncing on connector", e);
         }
-        actions.afterAll(syncTask, results);
+        actions.afterAll(handler, results);
 
         final String result = createReport(results, 
syncTask.getResource().getSyncTraceLevel(), dryRun);
 

Modified: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncopeSyncResultHandler.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncopeSyncResultHandler.java?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncopeSyncResultHandler.java
 (original)
+++ 
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncopeSyncResultHandler.java
 Mon Dec 24 09:56:52 2012
@@ -70,6 +70,7 @@ import org.apache.syncope.types.Resource
 import org.apache.syncope.types.SyncPolicySpec;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeUtil;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
 import org.identityconnectors.framework.common.objects.OperationalAttributes;
 import org.identityconnectors.framework.common.objects.SyncDelta;
 import org.identityconnectors.framework.common.objects.SyncDeltaType;
@@ -177,22 +178,42 @@ public class SyncopeSyncResultHandler im
 
     private boolean dryRun;
 
+    public SyncActions getActions() {
+        return actions;
+    }
+
     public void setActions(final SyncActions actions) {
         this.actions = actions;
     }
 
+    public Collection<SyncResult> getResults() {
+        return results;
+    }
+
     public void setResults(final Collection<SyncResult> results) {
         this.results = results;
     }
 
+    public SyncTask getSyncTask() {
+        return syncTask;
+    }
+
     public void setSyncTask(final SyncTask syncTask) {
         this.syncTask = syncTask;
     }
 
+    public ConflictResolutionAction getResAct() {
+        return resAct;
+    }
+
     public void setResAct(final ConflictResolutionAction resAct) {
         this.resAct = resAct;
     }
 
+    public boolean isDryRun() {
+        return dryRun;
+    }
+
     public void setDryRun(final boolean dryRun) {
         this.dryRun = dryRun;
     }
@@ -283,7 +304,7 @@ public class SyncopeSyncResultHandler im
         return result;
     }
 
-    private List<Long> findByAttributableSearch(final SyncDelta delta, final 
SyncPolicySpec policySpec,
+    private List<Long> findByAttributableSearch(final ConnectorObject connObj, 
final SyncPolicySpec policySpec,
             final AttributableUtil attrUtil) {
 
         final List<Long> result = new ArrayList<Long>();
@@ -293,7 +314,7 @@ public class SyncopeSyncResultHandler im
         final Map<String, Attribute> extValues = new HashMap<String, 
Attribute>();
 
         for (AbstractMappingItem item : 
attrUtil.getMappingItems(syncTask.getResource())) {
-            extValues.put(item.getIntAttrName(), 
delta.getObject().getAttributeByName(item.getExtAttrName()));
+            extValues.put(item.getIntAttrName(), 
connObj.getAttributeByName(item.getExtAttrName()));
         }
 
         // search for user/role by attribute(s) specified in the policy
@@ -352,15 +373,12 @@ public class SyncopeSyncResultHandler im
     /**
      * Find users / roles based on mapped uid value (or previous uid value, if 
updated).
      *
-     * @param delta sync delta
+     * @param uid for finding by account id
+     * @param connObj for finding by attribute value
      * @param attrUtil attributable util
      * @return list of matching users / roles
      */
-    protected List<Long> findExisting(final SyncDelta delta, final 
AttributableUtil attrUtil) {
-        final String uid = delta.getPreviousUid() == null
-                ? delta.getUid().getUidValue()
-                : delta.getPreviousUid().getUidValue();
-
+    public List<Long> findExisting(final String uid, final ConnectorObject 
connObj, final AttributableUtil attrUtil) {
         SyncPolicySpec policySpec = null;
         if (syncTask.getResource().getSyncPolicy() != null) {
             policySpec = (SyncPolicySpec) 
syncTask.getResource().getSyncPolicy().getSpecification();
@@ -368,7 +386,7 @@ public class SyncopeSyncResultHandler im
 
         return policySpec == null || 
attrUtil.getAltSearchSchemas(policySpec).isEmpty()
                 ? findByAccountIdItem(uid, attrUtil)
-                : findByAttributableSearch(delta, policySpec, attrUtil);
+                : findByAttributableSearch(connObj, policySpec, attrUtil);
     }
 
     protected List<SyncResult> create(SyncDelta delta, final AttributableUtil 
attrUtil,
@@ -385,7 +403,7 @@ public class SyncopeSyncResultHandler im
 
         AbstractAttributableTO subjectTO = 
connObjectUtil.getAttributableTO(delta.getObject(), syncTask, attrUtil);
 
-        delta = actions.beforeCreate(delta, subjectTO);
+        delta = actions.beforeCreate(this, delta, subjectTO);
 
         if (dryRun) {
             result.setId(0L);
@@ -458,7 +476,7 @@ public class SyncopeSyncResultHandler im
             }
         }
 
-        actions.after(delta, subjectTO, result);
+        actions.after(this, delta, subjectTO, result);
         return Collections.singletonList(result);
     }
 
@@ -486,7 +504,7 @@ public class SyncopeSyncResultHandler im
                 try {
                     final AbstractAttributableMod mod = 
connObjectUtil.getAttributableMod(
                             id, delta.getObject(), subjectTO, syncTask, 
attrUtil);
-                    delta = actions.beforeUpdate(delta, subjectTO, mod);
+                    delta = actions.beforeUpdate(this, delta, subjectTO, mod);
 
                     result.setStatus(SyncResult.Status.SUCCESS);
                     result.setId(mod.getId());
@@ -532,7 +550,7 @@ public class SyncopeSyncResultHandler im
                     LOG.error("Could not update {} {}", attrUtil.getType(), 
delta.getUid().getUidValue(), e);
                 }
 
-                actions.after(delta, subjectTO, result);
+                actions.after(this, delta, subjectTO, result);
                 updResults.add(result);
             } catch (NotFoundException e) {
                 LOG.error("Could not find {} {}", attrUtil.getType(), id, e);
@@ -561,7 +579,7 @@ public class SyncopeSyncResultHandler im
                 AbstractAttributableTO subjectTO = AttributableType.USER == 
attrUtil.getType()
                         ? userDataBinder.getUserTO(id)
                         : roleDataBinder.getRoleTO(id);
-                delta = actions.beforeDelete(delta, subjectTO);
+                delta = actions.beforeDelete(this, delta, subjectTO);
 
                 final SyncResult result = new SyncResult();
                 result.setId(id);
@@ -604,7 +622,7 @@ public class SyncopeSyncResultHandler im
                     }
                 }
 
-                actions.after(delta, subjectTO, result);
+                actions.after(this, delta, subjectTO, result);
                 delResults.add(result);
             } catch (NotFoundException e) {
                 LOG.error("Could not find {} {}", attrUtil.getType(), id, e);
@@ -631,7 +649,10 @@ public class SyncopeSyncResultHandler im
 
         AttributableUtil attrUtil = 
AttributableUtil.getInstance(delta.getObject().getObjectClass());
 
-        final List<Long> subjects = findExisting(delta, attrUtil);
+        final String uid = delta.getPreviousUid() == null
+                ? delta.getUid().getUidValue()
+                : delta.getPreviousUid().getUidValue();
+        final List<Long> subjects = findExisting(uid, delta.getObject(), 
attrUtil);
 
         if (SyncDeltaType.CREATE_OR_UPDATE == delta.getDeltaType()) {
             if (subjects.isEmpty()) {

Modified: 
syncope/trunk/core/src/main/java/org/apache/syncope/core/workflow/user/activiti/SyncopeUserQueryImpl.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/workflow/user/activiti/SyncopeUserQueryImpl.java?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- 
syncope/trunk/core/src/main/java/org/apache/syncope/core/workflow/user/activiti/SyncopeUserQueryImpl.java
 (original)
+++ 
syncope/trunk/core/src/main/java/org/apache/syncope/core/workflow/user/activiti/SyncopeUserQueryImpl.java
 Mon Dec 24 09:56:52 2012
@@ -48,7 +48,6 @@ public class SyncopeUserQueryImpl implem
     private List<User> result;
 
     public SyncopeUserQueryImpl(final UserDAO userDAO, final RoleDAO roleDAO, 
final EntitlementDAO entitlementDAO) {
-
         this.userDAO = userDAO;
         this.roleDAO = roleDAO;
         this.entitlementDAO = entitlementDAO;
@@ -133,20 +132,22 @@ public class SyncopeUserQueryImpl implem
         return new UserEntity(syncopeUser.getUsername());
     }
 
-    private void execute(int page, int itemsPerPage) {
+    private void execute(final int page, final int itemsPerPage) {
         if (username != null) {
             SyncopeUser user = userDAO.find(username);
-            if (user != null) {
+            if (user == null) {
+                result = Collections.<User>emptyList();
+            } else {
                 if (memberOf == null || user.getRoleIds().contains(memberOf)) {
                     result = Collections.singletonList(fromSyncopeUser(user));
                 }
-            } else {
-                result = Collections.emptyList();
             }
         }
         if (memberOf != null) {
             SyncopeRole role = roleDAO.find(memberOf);
-            if (role != null) {
+            if (role == null) {
+                result = Collections.<User>emptyList();
+            } else {
                 result = new ArrayList<User>();
                 List<Membership> memberships = roleDAO.findMemberships(role);
                 User user;
@@ -156,8 +157,6 @@ public class SyncopeUserQueryImpl implem
                         result.add(user);
                     }
                 }
-            } else {
-                result = Collections.emptyList();
             }
         }
         // THIS CAN BE *VERY* DANGEROUS
@@ -210,7 +209,7 @@ public class SyncopeUserQueryImpl implem
     }
 
     @Override
-    public UserQuery potentialStarter(String string) {
+    public UserQuery potentialStarter(final String string) {
         throw new UnsupportedOperationException();
     }
 }

Modified: 
syncope/trunk/core/src/test/java/org/apache/syncope/core/quartz/TestSyncActions.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/test/java/org/apache/syncope/core/quartz/TestSyncActions.java?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- 
syncope/trunk/core/src/test/java/org/apache/syncope/core/quartz/TestSyncActions.java
 (original)
+++ 
syncope/trunk/core/src/test/java/org/apache/syncope/core/quartz/TestSyncActions.java
 Mon Dec 24 09:56:52 2012
@@ -24,6 +24,7 @@ import org.apache.syncope.client.mod.Att
 import org.apache.syncope.client.to.AbstractAttributableTO;
 import org.apache.syncope.client.to.AttributeTO;
 import org.apache.syncope.core.sync.DefaultSyncActions;
+import org.apache.syncope.core.sync.SyncopeSyncResultHandler;
 import org.identityconnectors.framework.common.objects.SyncDelta;
 import org.quartz.JobExecutionException;
 
@@ -32,8 +33,8 @@ public class TestSyncActions extends Def
     private int counter = 0;
 
     @Override
-    public <T extends AbstractAttributableTO> SyncDelta beforeCreate(final 
SyncDelta delta, final T subject)
-            throws JobExecutionException {
+    public <T extends AbstractAttributableTO> SyncDelta beforeCreate(final 
SyncopeSyncResultHandler handler,
+            final SyncDelta delta, final T subject) throws 
JobExecutionException {
 
         AttributeTO attrTO = null;
         for (int i = 0; i < subject.getAttributes().size(); i++) {
@@ -53,7 +54,8 @@ public class TestSyncActions extends Def
 
     @Override
     public <T extends AbstractAttributableTO, K extends 
AbstractAttributableMod> SyncDelta beforeUpdate(
-            final SyncDelta delta, final T subject, final K subjectMod) throws 
JobExecutionException {
+            final SyncopeSyncResultHandler handler, final SyncDelta delta, 
final T subject, final K subjectMod)
+            throws JobExecutionException {
 
         subjectMod.addAttributeToBeRemoved("fullname");
 

Modified: 
syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/TaskTestITCase.java
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/TaskTestITCase.java?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- 
syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/TaskTestITCase.java
 (original)
+++ 
syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/TaskTestITCase.java
 Mon Dec 24 09:56:52 2012
@@ -362,10 +362,12 @@ public class TaskTestITCase extends Abst
 
         TaskExecTO execution = execTask(SyncTaskTO.class, actual.getId(), 20, 
false);
 
+        // 1. verify execution status
         final String status = execution.getStatus();
         assertNotNull(status);
         assertTrue(PropagationTaskExecStatus.valueOf(status).isSuccessful());
 
+        // 2. verify that synchronized role is found, with expected attributes
         final AttributableCond rolenameLeafCond = new 
AttributableCond(AttributableCond.Type.EQ);
         rolenameLeafCond.setSchema("name");
         rolenameLeafCond.setExpression("testLDAPGroup");
@@ -379,6 +381,14 @@ public class TaskTestITCase extends Abst
         assertEquals("testLDAPGroup", roleTO.getName());
         assertEquals(8L, roleTO.getParent());
         assertEquals("true", 
roleTO.getAttributeMap().get("show").getValues().get(0));
+
+        // 3. verify that LDAP group membership is propagated as Syncope role 
membership
+        final MembershipCond membershipCond = new MembershipCond();
+        membershipCond.setRoleId(roleTO.getId());
+        final List<UserTO> members = 
Arrays.asList(restTemplate.postForObject(BASE_URL + "user/search",
+                NodeCond.getLeafCond(membershipCond), UserTO[].class));
+        assertNotNull(members);
+        assertEquals(1, members.size());
     }
 
     @Test

Modified: syncope/trunk/core/src/test/resources/content.xml
URL: 
http://svn.apache.org/viewvc/syncope/trunk/core/src/test/resources/content.xml?rev=1425615&r1=1425614&r2=1425615&view=diff
==============================================================================
--- syncope/trunk/core/src/test/resources/content.xml (original)
+++ syncope/trunk/core/src/test/resources/content.xml Mon Dec 24 09:56:52 2012
@@ -542,7 +542,7 @@ under the License.
   <UMapping id="11" resource_name="resource-ldap"
             accountlink="&apos;uid=&apos; + username + 
&apos;,ou=people,o=isp&apos;"/>
   <UMappingItem id="311" accountid="1" password="0" mapping_id="11"
-                extAttrName="__NAME__" intAttrName="Username" 
intMappingType="Username"
+                extAttrName="__UID__" intAttrName="Username" 
intMappingType="Username"
                 mandatoryCondition="true"/>
   <UMappingItem id="312" accountid="0" password="1" mapping_id="11"
                 extAttrName="__PASSWORD__" intAttrName="Password" 
intMappingType="Password"
@@ -551,7 +551,7 @@ under the License.
                 extAttrName="sn" intAttrName="surname" 
intMappingType="UserSchema"
                 mandatoryCondition="true"/>
   <UMappingItem id="314" accountid="0" password="0" mapping_id="11"
-                extAttrName="cn" intAttrName="firstname" 
intMappingType="UserSchema"
+                extAttrName="cn" intAttrName="fullname" 
intMappingType="UserSchema"
                 mandatoryCondition="true"/>
   <UMappingItem id="315" accountid="0" password="0" mapping_id="11"
                 extAttrName="mail" intAttrName="email" 
intMappingType="UserSchema"
@@ -562,6 +562,9 @@ under the License.
   <UMappingItem id="317" accountid="0" password="0" mapping_id="11"
                 extAttrName="postalAddress" intAttrName="postalAddress" 
intMappingType="MembershipSchema"
                 mandatoryCondition="false"/>
+  <UMappingItem id="318" accountid="0" password="0" mapping_id="11"
+                extAttrName="mail" intAttrName="userId" 
intMappingType="UserSchema"
+                mandatoryCondition="false"/>
   <RMapping id="1" resource_name="resource-ldap"
             accountlink="&apos;cn=&apos; + name + 
&apos;,ou=groups,o=isp&apos;"/>
   <RMappingItem id="1" accountid="1" password="0" mapping_id="1"
@@ -626,8 +629,9 @@ under the License.
         fullReconciliation="1" performCreate="1" performDelete="1" 
performUpdate="1" syncStatus="0"
         jobClassName="org.apache.syncope.core.sync.SyncJob"/>
   <Task DTYPE="SyncTask" id="11" name="LDAP Sync Task" 
resource_name="resource-ldap"
-          fullReconciliation="1" performCreate="1" performDelete="1" 
performUpdate="1" syncStatus="0"
-          jobClassName="org.apache.syncope.core.sync.SyncJob"/>
+        fullReconciliation="1" performCreate="1" performDelete="1" 
performUpdate="1" syncStatus="0"
+        
actionsClassName="org.apache.syncope.core.sync.LDAPMembershipSyncActions"  
+        jobClassName="org.apache.syncope.core.sync.SyncJob"/>
         
   <NotificationTask_recipients notificationtask_id="8" 
address="recipi...@prova.org"/>
 


Reply via email to