You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2014/01/07 15:33:45 UTC

svn commit: r1556227 [3/3] - in /syncope/trunk: common/src/main/java/org/apache/syncope/common/services/ common/src/main/java/org/apache/syncope/common/to/ common/src/main/java/org/apache/syncope/common/types/ common/src/main/java/org/apache/syncope/co...

Copied: syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java (from r1554763, syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java)
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java?p2=syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java&p1=syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java&r1=1554763&r2=1556227&rev=1556227&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java Tue Jan  7 14:33:44 2014
@@ -18,127 +18,54 @@
  */
 package org.apache.syncope.core.sync.impl;
 
-import java.util.AbstractMap;
+import static org.apache.syncope.core.sync.impl.AbstractSyncopeResultHandler.LOG;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.mod.AttributeMod;
-import org.apache.syncope.common.mod.RoleMod;
-import org.apache.syncope.common.mod.UserMod;
-import org.apache.syncope.core.persistence.dao.search.AttributableCond;
-import org.apache.syncope.core.persistence.dao.search.AttributeCond;
-import org.apache.syncope.core.persistence.dao.search.SearchCond;
-import org.apache.syncope.common.to.AbstractAttributableTO;
-import org.apache.syncope.common.to.AttributeTO;
-import org.apache.syncope.common.to.RoleTO;
-import org.apache.syncope.common.to.UserTO;
+import java.util.Set;
 import org.apache.syncope.common.types.AttributableType;
 import org.apache.syncope.common.types.AuditElements;
 import org.apache.syncope.common.types.AuditElements.Result;
-import org.apache.syncope.common.types.ConflictResolutionAction;
-import org.apache.syncope.common.types.MappingPurpose;
 import org.apache.syncope.common.types.ResourceOperation;
-import org.apache.syncope.common.types.SyncPolicySpec;
 import org.apache.syncope.core.audit.AuditManager;
 import org.apache.syncope.core.connid.ConnObjectUtil;
 import org.apache.syncope.core.notification.NotificationManager;
-import org.apache.syncope.core.persistence.beans.AbstractAttrValue;
 import org.apache.syncope.core.persistence.beans.AbstractAttributable;
 import org.apache.syncope.core.persistence.beans.AbstractMappingItem;
-import org.apache.syncope.core.persistence.beans.AbstractNormalSchema;
-import org.apache.syncope.core.persistence.beans.PropagationTask;
-import org.apache.syncope.core.persistence.beans.SyncPolicy;
-import org.apache.syncope.core.persistence.beans.SyncTask;
+import org.apache.syncope.core.persistence.beans.PushTask;
 import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
 import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
-import org.apache.syncope.core.persistence.dao.AttributableSearchDAO;
-import org.apache.syncope.core.persistence.dao.EntitlementDAO;
-import org.apache.syncope.core.persistence.dao.NotFoundException;
-import org.apache.syncope.core.persistence.dao.PolicyDAO;
-import org.apache.syncope.core.persistence.dao.RoleDAO;
-import org.apache.syncope.core.persistence.dao.SchemaDAO;
-import org.apache.syncope.core.persistence.dao.UserDAO;
-import org.apache.syncope.core.persistence.dao.search.OrderByClause;
-import org.apache.syncope.core.persistence.validation.attrvalue.ParsingValidationException;
-import org.apache.syncope.core.propagation.PropagationByResource;
-import org.apache.syncope.core.propagation.PropagationException;
-import org.apache.syncope.core.propagation.PropagationTaskExecutor;
-import org.apache.syncope.core.propagation.Connector;
-import org.apache.syncope.core.propagation.impl.PropagationManager;
-import org.apache.syncope.core.rest.controller.UnauthorizedRoleException;
-import org.apache.syncope.core.rest.data.AttributableTransformer;
+import org.apache.syncope.core.propagation.TimeoutException;
+import org.apache.syncope.core.propagation.impl.AbstractPropagationTaskExecutor;
 import org.apache.syncope.core.rest.data.RoleDataBinder;
 import org.apache.syncope.core.rest.data.UserDataBinder;
-import org.apache.syncope.core.sync.SyncActions;
+import org.apache.syncope.core.sync.PushActions;
 import org.apache.syncope.core.sync.SyncResult;
-import org.apache.syncope.core.sync.SyncCorrelationRule;
 import org.apache.syncope.core.util.AttributableUtil;
-import org.apache.syncope.core.util.EntitlementUtil;
-import org.apache.syncope.core.workflow.WorkflowResult;
-import org.apache.syncope.core.workflow.role.RoleWorkflowAdapter;
-import org.apache.syncope.core.workflow.user.UserWorkflowAdapter;
+import org.apache.syncope.core.util.MappingUtil;
 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.Name;
 import org.identityconnectors.framework.common.objects.ObjectClass;
-import org.identityconnectors.framework.common.objects.OperationalAttributes;
-import org.identityconnectors.framework.common.objects.SyncDelta;
-import org.identityconnectors.framework.common.objects.SyncDeltaType;
-import org.identityconnectors.framework.common.objects.SyncResultsHandler;
-import org.identityconnectors.framework.common.objects.filter.EqualsFilter;
+import org.identityconnectors.framework.common.objects.Uid;
 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;
 
-public class SyncopeSyncResultHandler implements SyncResultsHandler {
+public class SyncopePushResultHandler extends AbstractSyncopeResultHandler {
 
     /**
-     * Logger.
-     */
-    protected static final Logger LOG = LoggerFactory.getLogger(SyncopeSyncResultHandler.class);
-
-    /**
-     * Policy DAO.
-     */
-    @Autowired
-    protected PolicyDAO policyDAO;
-
-    /**
-     * Entitlement DAO.
-     */
-    @Autowired
-    protected EntitlementDAO entitlementDAO;
-
-    /**
-     * Schema DAO.
-     */
-    @Autowired
-    protected SchemaDAO schemaDAO;
-
-    /**
-     * User DAO.
-     */
-    @Autowired
-    protected UserDAO userDAO;
-
-    /**
-     * Role DAO.
+     * User data binder.
      */
     @Autowired
-    protected RoleDAO roleDAO;
+    protected UserDataBinder userDataBinder;
 
     /**
-     * Search DAO.
+     * Role data binder.
      */
     @Autowired
-    protected AttributableSearchDAO searchDAO;
+    protected RoleDataBinder roleDataBinder;
 
     /**
      * ConnectorObject util.
@@ -147,42 +74,6 @@ public class SyncopeSyncResultHandler im
     protected ConnObjectUtil connObjectUtil;
 
     /**
-     * User workflow adapter.
-     */
-    @Autowired
-    protected UserWorkflowAdapter uwfAdapter;
-
-    /**
-     * Role workflow adapter.
-     */
-    @Autowired
-    protected RoleWorkflowAdapter rwfAdapter;
-
-    /**
-     * Propagation Manager.
-     */
-    @Autowired
-    protected PropagationManager propagationManager;
-
-    /**
-     * PropagationTask executor.
-     */
-    @Autowired
-    protected PropagationTaskExecutor taskExecutor;
-
-    /**
-     * User data binder.
-     */
-    @Autowired
-    protected UserDataBinder userDataBinder;
-
-    /**
-     * Role data binder.
-     */
-    @Autowired
-    protected RoleDataBinder roleDataBinder;
-
-    /**
      * Notification Manager.
      */
     @Autowired
@@ -194,85 +85,39 @@ public class SyncopeSyncResultHandler im
     @Autowired
     protected AuditManager auditManager;
 
-    @Autowired
-    protected AttributableTransformer attrTransformer;
-
-    /**
-     * Syncing connector.
-     */
-    protected Connector connector;
+    protected Map<Long, String> roleOwnerMap = new HashMap<Long, String>();
 
     /**
      * SyncJob actions.
      */
-    protected SyncActions actions;
-
-    protected Collection<SyncResult> results;
-
-    protected SyncTask syncTask;
-
-    protected ConflictResolutionAction resAct;
+    protected PushActions actions;
 
-    protected boolean dryRun;
+    protected PushTask syncTask;
 
-    protected Map<Long, String> roleOwnerMap = new HashMap<Long, String>();
-
-    public Connector getConnector() {
-        return connector;
-    }
-
-    public void setConnector(final Connector connector) {
-        this.connector = connector;
-    }
-
-    public SyncActions getActions() {
+    public PushActions getActions() {
         return actions;
     }
 
-    public void setActions(final SyncActions actions) {
+    public void setActions(final PushActions actions) {
         this.actions = actions;
     }
 
-    public Collection<SyncResult> getResults() {
-        return results;
-    }
-
-    public void setResults(final Collection<SyncResult> results) {
-        this.results = results;
-    }
-
-    public SyncTask getSyncTask() {
+    public PushTask getSyncTask() {
         return syncTask;
     }
 
-    public void setSyncTask(final SyncTask syncTask) {
+    public void setSyncTask(final PushTask 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;
-    }
-
     public Map<Long, String> getRoleOwnerMap() {
         return roleOwnerMap;
     }
 
-    @Override
-    public boolean handle(final SyncDelta delta) {
+    @Transactional
+    public boolean handle(final AbstractAttributable attributable) {
         try {
-            doHandle(delta);
+            doHandle(attributable);
             return true;
         } catch (JobExecutionException e) {
             LOG.error("Synchronization failed", e);
@@ -280,720 +125,139 @@ public class SyncopeSyncResultHandler im
         }
     }
 
-    protected List<Long> findByAccountIdItem(final String uid, final AttributableUtil attrUtil) {
-        final List<Long> result = new ArrayList<Long>();
-
-        final AbstractMappingItem accountIdItem = attrUtil.getAccountIdItem(syncTask.getResource());
-        switch (accountIdItem.getIntMappingType()) {
-            case UserSchema:
-            case RoleSchema:
-                final AbstractAttrValue value = attrUtil.newAttrValue();
-
-                AbstractNormalSchema schema = schemaDAO.find(accountIdItem.getIntAttrName(), attrUtil.schemaClass());
-                if (schema == null) {
-                    value.setStringValue(uid);
-                } else {
-                    try {
-                        value.parseValue(schema, uid);
-                    } catch (ParsingValidationException e) {
-                        LOG.error("While parsing provided __UID__ {}", uid, e);
-                        value.setStringValue(uid);
-                    }
-                }
-
-                List<AbstractAttributable> subjects =
-                        userDAO.findByAttrValue(accountIdItem.getIntAttrName(), value, attrUtil);
-                for (AbstractAttributable subject : subjects) {
-                    result.add(subject.getId());
-                }
-                break;
-
-            case UserDerivedSchema:
-            case RoleDerivedSchema:
-                subjects = userDAO.findByDerAttrValue(accountIdItem.getIntAttrName(), uid, attrUtil);
-                for (AbstractAttributable subject : subjects) {
-                    result.add(subject.getId());
-                }
-                break;
-
-            case Username:
-                SyncopeUser user = userDAO.find(uid);
-                if (user != null) {
-                    result.add(user.getId());
-                }
-                break;
-
-            case UserId:
-                user = userDAO.find(Long.parseLong(uid));
-                if (user != null) {
-                    result.add(user.getId());
-                }
-                break;
-
-            case RoleName:
-                List<SyncopeRole> roles = roleDAO.find(uid);
-                for (SyncopeRole role : roles) {
-                    result.add(role.getId());
-                }
-                break;
-
-            case RoleId:
-                SyncopeRole role = roleDAO.find(Long.parseLong(uid));
-                if (role != null) {
-                    result.add(role.getId());
-                }
-                break;
-
-            default:
-                LOG.error("Invalid accountId type '{}'", accountIdItem.getIntMappingType());
-        }
-
-        return result;
-    }
-
-    protected List<Long> search(final SearchCond searchCond, final AttributableUtil attrUtil) {
-        final List<Long> result = new ArrayList<Long>();
-
-        final List<AbstractAttributable> subjects = searchDAO.search(
-                EntitlementUtil.getRoleIds(entitlementDAO.findAll()),
-                searchCond, Collections.<OrderByClause>emptyList(), attrUtil);
-        for (AbstractAttributable subject : subjects) {
-            result.add(subject.getId());
-        }
-
-        return result;
-    }
-
-    protected List<Long> findByCorrelationRule(
-            final ConnectorObject connObj, final SyncCorrelationRule rule, final AttributableUtil attrUtil) {
-
-        return search(rule.getSearchCond(connObj), attrUtil);
-    }
-
-    protected List<Long> findByAttributableSearch(
-            final ConnectorObject connObj, final List<String> altSearchSchemas, final AttributableUtil attrUtil) {
-
-        // search for external attribute's name/value of each specified name
-        final Map<String, Attribute> extValues = new HashMap<String, Attribute>();
-
-        for (AbstractMappingItem item
-                : attrUtil.getMappingItems(syncTask.getResource(), MappingPurpose.SYNCHRONIZATION)) {
-
-            extValues.put(item.getIntAttrName(), connObj.getAttributeByName(item.getExtAttrName()));
-        }
-
-        // search for user/role by attribute(s) specified in the policy
-        SearchCond searchCond = null;
-
-        for (String schema : altSearchSchemas) {
-            Attribute value = extValues.get(schema);
-
-            AttributeCond.Type type;
-            String expression = null;
-
-            if (value == null || value.getValue() == null || value.getValue().isEmpty()
-                    || (value.getValue().size() == 1 && value.getValue().get(0) == null)) {
-                type = AttributeCond.Type.ISNULL;
-            } else {
-                type = AttributeCond.Type.EQ;
-                expression = value.getValue().size() > 1
-                        ? value.getValue().toString()
-                        : value.getValue().get(0).toString();
-            }
-
-            SearchCond nodeCond;
-            // users: just id or username can be selected to be used
-            // roles: just id or name can be selected to be used
-            if ("id".equalsIgnoreCase(schema) || "username".equalsIgnoreCase(schema)
-                    || "name".equalsIgnoreCase(schema)) {
-
-                AttributableCond cond = new AttributableCond();
-                cond.setSchema(schema);
-                cond.setType(type);
-                cond.setExpression(expression);
-
-                nodeCond = SearchCond.getLeafCond(cond);
-            } else {
-                AttributeCond cond = new AttributeCond();
-                cond.setSchema(schema);
-                cond.setType(type);
-                cond.setExpression(expression);
-
-                nodeCond = SearchCond.getLeafCond(cond);
-            }
-
-            searchCond = searchCond == null
-                    ? nodeCond
-                    : SearchCond.getAndCond(searchCond, nodeCond);
-        }
-
-        return search(searchCond, attrUtil);
-    }
-
     /**
-     * Find users / roles based on mapped uid value (or previous uid value, if updated).
+     * Look into SyncDelta and take necessary actions (create / update / delete) on user(s).
      *
-     * @param uid for finding by account id
-     * @param connObj for finding by attribute value
-     * @param attrUtil attributable util
-     * @return list of matching users / roles
+     * @param delta returned by the underlying connector
+     * @throws JobExecutionException in case of synchronization failure.
      */
-    protected List<Long> findExisting(final String uid, final ConnectorObject connObj,
-            final AttributableUtil attrUtil) {
-
-        SyncPolicySpec syncPolicySpec = null;
-        if (syncTask.getResource().getSyncPolicy() == null) {
-            SyncPolicy globalSP = policyDAO.getGlobalSyncPolicy();
-            if (globalSP != null) {
-                syncPolicySpec = globalSP.<SyncPolicySpec>getSpecification();
-            }
-        } else {
-            syncPolicySpec = syncTask.getResource().getSyncPolicy().<SyncPolicySpec>getSpecification();
-        }
-
-        SyncCorrelationRule syncRule = null;
-        List<String> altSearchSchemas = null;
+    protected final void doHandle(final AbstractAttributable attributable)
+            throws JobExecutionException {
 
-        if (syncPolicySpec != null) {
-            syncRule = attrUtil.getCorrelationRule(syncPolicySpec);
-            altSearchSchemas = attrUtil.getAltSearchSchemas(syncPolicySpec);
+        if (results == null) {
+            results = new ArrayList<SyncResult>();
         }
 
-        return syncRule == null ? altSearchSchemas == null || altSearchSchemas.isEmpty()
-                ? findByAccountIdItem(uid, attrUtil)
-                : findByAttributableSearch(connObj, altSearchSchemas, attrUtil)
-                : findByCorrelationRule(connObj, syncRule, attrUtil);
-    }
+        final AttributableUtil attrUtil = AttributableUtil.getInstance(attributable);
 
-    public Long findMatchingAttributableId(final ObjectClass objectClass, final String name) {
-        Long result = null;
+        final SyncResult result = new SyncResult();
+        results.add(result);
 
-        final AttributableUtil attrUtil = AttributableUtil.getInstance(objectClass);
+        result.setId(attributable.getId());
+        result.setSubjectType(attrUtil.getType());
 
-        final List<ConnectorObject> found = connector.search(objectClass,
-                new EqualsFilter(new Name(name)), connector.getOperationOptions(
-                        attrUtil.getMappingItems(syncTask.getResource(), MappingPurpose.SYNCHRONIZATION)));
+        final AbstractAttributable toBeHandled;
+        final Boolean enabled;
 
-        if (found.isEmpty()) {
-            LOG.debug("No {} found on {} with __NAME__ {}", objectClass, syncTask.getResource(), name);
+        if (attrUtil.getType() == AttributableType.USER) {
+            toBeHandled = userDataBinder.getUserFromId(attributable.getId());
+            result.setName(((SyncopeUser) toBeHandled).getUsername());
+            enabled = getSyncTask().isSyncStatus()
+                    ? ((SyncopeUser) toBeHandled).isSuspended() ? Boolean.FALSE : Boolean.TRUE
+                    : null;
         } else {
-            if (found.size() > 1) {
-                LOG.warn("More than one {} found on {} with __NAME__ {} - taking first only",
-                        objectClass, syncTask.getResource(), name);
-            }
-
-            ConnectorObject connObj = found.iterator().next();
-            final List<Long> subjectIds = findExisting(connObj.getUid().getUidValue(), connObj, attrUtil);
-            if (subjectIds.isEmpty()) {
-                LOG.debug("No matching {} found for {}, aborting", attrUtil.getType(), connObj);
-            } else {
-                if (subjectIds.size() > 1) {
-                    LOG.warn("More than one {} found {} - taking first only", attrUtil.getType(), subjectIds);
-                }
-
-                result = subjectIds.iterator().next();
-            }
+            toBeHandled = roleDataBinder.getRoleFromId(attributable.getId());
+            result.setName(((SyncopeRole) toBeHandled).getName());
+            enabled = null;
         }
 
-        return result;
-    }
+        LOG.debug("Propagating {} with ID {} towards {}",
+                attrUtil.getType(), toBeHandled.getId(), getSyncTask().getResource());
+
+        Object output = null;
+        Result resultStatus = null;
+        ConnectorObject beforeObj = null;
+        Map.Entry<String, Set<Attribute>> values = null;
 
-    protected Boolean readEnabled(final ConnectorObject connectorObject) {
-        Boolean enabled = null;
-        if (syncTask.isSyncStatus()) {
-            Attribute status = AttributeUtil.find(OperationalAttributes.ENABLE_NAME, connectorObject.getAttributes());
-            if (status != null && status.getValue() != null && !status.getValue().isEmpty()) {
-                enabled = (Boolean) status.getValue().get(0);
+        try {
+            values = MappingUtil.prepareAttributes(
+                    attrUtil, // attributable util
+                    toBeHandled, // attributable (user or role)
+                    null, // current password if decode is possible; generate otherwise
+                    true, // propagate password (if required)
+                    null, // no vir attrs to be removed
+                    null, // propagate current vir attr values
+                    enabled, // propagate status (suspended or not) if required
+                    getSyncTask().getResource()); // target external resource
+
+            final ObjectClass oclass =
+                    attrUtil.getType() == AttributableType.USER ? ObjectClass.ACCOUNT : ObjectClass.GROUP;
+
+            // Try to read remote object (user / group) BEFORE any actual operation
+            beforeObj = getRemoteObject(oclass, values.getKey(), getSyncTask().getResource().getName());
+
+            if (beforeObj == null) {
+                result.setOperation(ResourceOperation.CREATE);
+                actions.beforeCreate(this, toBeHandled, values);
+            } else {
+                result.setOperation(ResourceOperation.UPDATE);
+                actions.beforeUpdate(this, toBeHandled, values);
             }
-        }
-
-        return enabled;
-    }
-
-    protected List<SyncResult> create(SyncDelta delta, final AttributableUtil attrUtil, final boolean dryRun)
-            throws JobExecutionException {
 
-        if (!syncTask.isPerformCreate()) {
-            LOG.debug("SyncTask not configured for create");
-            return Collections.<SyncResult>emptyList();
-        }
+            AbstractPropagationTaskExecutor.createOrUpdate(
+                    oclass,
+                    values.getKey(),
+                    values.getValue(),
+                    getSyncTask().getResource().getName(),
+                    getSyncTask().getResource().getPropagationMode(),
+                    beforeObj,
+                    connector,
+                    new HashSet<String>(),
+                    connObjectUtil);
 
-        final SyncResult result = new SyncResult();
-        result.setOperation(ResourceOperation.CREATE);
-        result.setSubjectType(attrUtil.getType());
-        result.setStatus(SyncResult.Status.SUCCESS);
-
-        AbstractAttributableTO subjectTO = connObjectUtil.getAttributableTO(delta.getObject(), syncTask, attrUtil);
-
-        delta = actions.beforeCreate(this, delta, subjectTO);
-
-        // Attributable transformation (if configured)
-        AbstractAttributableTO actual = attrTransformer.transform(subjectTO);
-        LOG.debug("Transformed: {}", actual);
-
-        if (dryRun) {
-            result.setId(0L);
-            if (actual instanceof UserTO) {
-                result.setName(((UserTO) actual).getUsername());
-            }
-            if (actual instanceof RoleTO) {
-                result.setName(((RoleTO) actual).getName());
-            }
-        } else {
-            Object output = null;
-            Result resultStatus;
+            result.setStatus(SyncResult.Status.SUCCESS);
+            resultStatus = AuditElements.Result.SUCCESS;
+        } catch (Exception e) {
+            result.setStatus(SyncResult.Status.FAILURE);
+            result.setMessage(e.getMessage());
+            resultStatus = AuditElements.Result.FAILURE;
+            output = e;
+
+            LOG.warn("Error pushing {} towards {}", toBeHandled, getSyncTask().getResource(), e);
+            throw new JobExecutionException(e);
+        } finally {
 
-            try {
-                if (AttributableType.USER == attrUtil.getType()) {
-                    Boolean enabled = readEnabled(delta.getObject());
-                    WorkflowResult<Map.Entry<Long, Boolean>> created =
-                            uwfAdapter.create((UserTO) actual, true, enabled);
-
-                    List<PropagationTask> tasks = propagationManager.getUserCreateTaskIds(created,
-                            ((UserTO) actual).getPassword(), actual.getVirAttrs(),
-                            Collections.singleton(syncTask.getResource().getName()));
-
-                    taskExecutor.execute(tasks);
-
-                    actual = userDataBinder.getUserTO(created.getResult().getKey());
-
-                    result.setId(created.getResult().getKey());
-                    result.setName(((UserTO) actual).getUsername());
-                } else if (AttributableType.ROLE == attrUtil.getType()) {
-                    WorkflowResult<Long> created = rwfAdapter.create((RoleTO) actual);
-                    AttributeTO roleOwner = actual.getAttrMap().get(StringUtils.EMPTY);
-                    if (roleOwner != null) {
-                        roleOwnerMap.put(created.getResult(), roleOwner.getValues().iterator().next());
-                    }
-
-                    EntitlementUtil.extendAuthContext(created.getResult());
-
-                    List<PropagationTask> tasks = propagationManager.getRoleCreateTaskIds(created,
-                            actual.getVirAttrs(), Collections.singleton(syncTask.getResource().getName()));
-
-                    taskExecutor.execute(tasks);
-
-                    actual = roleDataBinder.getRoleTO(created.getResult());
-
-                    result.setId(created.getResult());
-                    result.setName(((RoleTO) actual).getName());
-                }
-                output = actual;
-                resultStatus = Result.SUCCESS;
-
-            } catch (PropagationException e) {
-                // A propagation failure doesn't imply a synchronization failure.
-                // The propagation exception status will be reported into the propagation task execution.
-                LOG.error("Could not propagate {} {}", attrUtil.getType(), delta.getUid().getUidValue(), e);
-                output = e;
-                resultStatus = Result.FAILURE;
-            } catch (Exception e) {
-                result.setStatus(SyncResult.Status.FAILURE);
-                result.setMessage(e.getMessage());
-                LOG.error("Could not create {} {} ", attrUtil.getType(), delta.getUid().getUidValue(), e);
-                output = e;
-                resultStatus = Result.FAILURE;
-            }
+            actions.after(this, toBeHandled, values, result);
 
             notificationManager.createTasks(
-                    AuditElements.EventCategoryType.SYNCHRONIZATION,
+                    AuditElements.EventCategoryType.PUSH,
                     AttributableType.USER.name().toLowerCase(),
                     syncTask.getResource().getName(),
-                    "create",
+                    result.getOperation() == null ? null : result.getOperation().name().toLowerCase(),
                     resultStatus,
-                    null, // searching for before object is too much expensive ... 
+                    beforeObj,
                     output,
-                    delta);
+                    toBeHandled);
 
             auditManager.audit(
-                    AuditElements.EventCategoryType.SYNCHRONIZATION,
+                    AuditElements.EventCategoryType.PUSH,
                     AttributableType.USER.name().toLowerCase(),
                     syncTask.getResource().getName(),
-                    "create",
+                    result.getOperation() == null ? null : result.getOperation().name().toLowerCase(),
                     resultStatus,
-                    null, // searching for before object is too much expensive ... 
+                    beforeObj,
                     output,
-                    delta);
+                    toBeHandled);
         }
-
-        actions.after(this, delta, actual, result);
-        return Collections.singletonList(result);
     }
 
-    protected Map.Entry<UserTO, UserTO> updateUser(final Long id, SyncDelta delta, final boolean dryRun,
-            final SyncResult result)
-            throws Exception {
-
-        final UserTO before = userDataBinder.getUserTO(id);
-        UserMod userMod = connObjectUtil.getAttributableMod(
-                id, delta.getObject(), before, syncTask, AttributableUtil.getInstance(AttributableType.USER));
-
-        delta = actions.beforeUpdate(this, delta, before, userMod);
-
-        if (dryRun) {
-            return new AbstractMap.SimpleEntry<UserTO, UserTO>(before, before);
-        }
+    private ConnectorObject getRemoteObject(
+            final ObjectClass oclass, final String accountId, final String resource) {
+        ConnectorObject obj = null;
 
-        // Attribute value transformation (if configured)
-        UserMod actual = attrTransformer.transform(userMod);
-        LOG.debug("Transformed: {}", actual);
-
-        WorkflowResult<Map.Entry<UserMod, Boolean>> updated;
         try {
-            updated = uwfAdapter.update(actual);
-        } catch (Exception e) {
-            LOG.error("Update of user {} failed, trying to sync its status anyway (if configured)", id, e);
 
-            result.setStatus(SyncResult.Status.FAILURE);
-            result.setMessage("Update failed, trying to sync status anyway (if configured)\n" + e.getMessage());
+            final Uid uid = new Uid(accountId);
 
-            updated = new WorkflowResult<Map.Entry<UserMod, Boolean>>(
-                    new AbstractMap.SimpleEntry<UserMod, Boolean>(userMod, false), new PropagationByResource(),
-                    new HashSet<String>());
-        }
+            connector.getObject(
+                    oclass, uid, connector.getOperationOptions(Collections.<AbstractMappingItem>emptySet()));
 
-        Boolean enabled = readEnabled(delta.getObject());
-        if (enabled != null) {
-            SyncopeUser user = userDAO.find(id);
-
-            WorkflowResult<Long> enableUpdate = null;
-            if (user.isSuspended() == null) {
-                enableUpdate = uwfAdapter.activate(id, null);
-            } else if (enabled && user.isSuspended()) {
-                enableUpdate = uwfAdapter.reactivate(id);
-            } else if (!enabled && !user.isSuspended()) {
-                enableUpdate = uwfAdapter.suspend(id);
-            }
-
-            if (enableUpdate != null) {
-                if (enableUpdate.getPropByRes() != null) {
-                    updated.getPropByRes().merge(enableUpdate.getPropByRes());
-                    updated.getPropByRes().purge();
-                }
-                updated.getPerformedTasks().addAll(enableUpdate.getPerformedTasks());
-            }
-        }
-
-        List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(
-                updated, updated.getResult().getKey().getPassword() != null,
-                Collections.singleton(syncTask.getResource().getName()));
-
-        taskExecutor.execute(tasks);
-
-        final UserTO after = userDataBinder.getUserTO(updated.getResult().getKey().getId());
-        actions.after(this, delta, after, result);
-
-        return new AbstractMap.SimpleEntry<UserTO, UserTO>(before, after);
-    }
-
-    protected Map.Entry<RoleTO, RoleTO> updateRole(
-            final Long id, SyncDelta delta, final boolean dryRun, final SyncResult result)
-            throws Exception {
-
-        final RoleTO before = roleDataBinder.getRoleTO(id);
-        RoleMod roleMod = connObjectUtil.getAttributableMod(
-                id, delta.getObject(), before, syncTask, AttributableUtil.getInstance(AttributableType.ROLE));
-
-        delta = actions.beforeUpdate(this, delta, before, roleMod);
-
-        if (dryRun) {
-            return new AbstractMap.SimpleEntry<RoleTO, RoleTO>(before, before);
-        }
-
-        // Attribute value transformation (if configured)
-        RoleMod actual = attrTransformer.transform(roleMod);
-        LOG.debug("Transformed: {}", actual);
-
-        WorkflowResult<Long> updated = rwfAdapter.update(actual);
-        String roleOwner = null;
-        for (AttributeMod attrMod : actual.getAttrsToUpdate()) {
-            if (attrMod.getSchema().isEmpty()) {
-                roleOwner = attrMod.getValuesToBeAdded().iterator().next();
-            }
-        }
-        if (roleOwner != null) {
-            roleOwnerMap.put(updated.getResult(), roleOwner);
-        }
-
-        List<PropagationTask> tasks = propagationManager.getRoleUpdateTaskIds(updated,
-                actual.getVirAttrsToRemove(),
-                actual.getVirAttrsToUpdate(),
-                Collections.singleton(syncTask.getResource().getName()));
-
-        taskExecutor.execute(tasks);
-
-        final RoleTO after = roleDataBinder.getRoleTO(updated.getResult());
-
-        actions.after(this, delta, after, result);
-
-        return new AbstractMap.SimpleEntry<RoleTO, RoleTO>(before, after);
-    }
-
-    protected List<SyncResult> update(SyncDelta delta, final List<Long> subjects, final AttributableUtil attrUtil,
-            final boolean dryRun)
-            throws JobExecutionException {
-
-        if (!syncTask.isPerformUpdate()) {
-            LOG.debug("SyncTask not configured for update");
-            return Collections.<SyncResult>emptyList();
-        }
-
-        LOG.debug("About to update {}", subjects);
-
-        List<SyncResult> updResults = new ArrayList<SyncResult>();
-
-        for (Long id : subjects) {
-            LOG.debug("About to update {}", id);
-
-            Object output = null;
-            AbstractAttributableTO before = null;
-            Result resultStatus;
-
-            final SyncResult result = new SyncResult();
-            result.setOperation(ResourceOperation.UPDATE);
-            result.setSubjectType(attrUtil.getType());
-            result.setStatus(SyncResult.Status.SUCCESS);
-            result.setId(id);
-
-            try {
-                final AbstractAttributableTO updated;
-                if (AttributableType.USER == attrUtil.getType()) {
-                    final Map.Entry<UserTO, UserTO> res = updateUser(id, delta, dryRun, result);
-                    before = res.getKey();
-                    updated = res.getValue();
-                    result.setName(((UserTO) updated).getUsername());
-                } else if (AttributableType.ROLE == attrUtil.getType()) {
-                    final Map.Entry<RoleTO, RoleTO> res = updateRole(id, delta, dryRun, result);
-                    before = res.getKey();
-                    updated = res.getValue();
-                    result.setName(((RoleTO) updated).getName());
-                } else {
-                    updated = null;
-                }
-                output = updated;
-                resultStatus = Result.SUCCESS;
-            } catch (PropagationException e) {
-                // A propagation failure doesn't imply a synchronization failure.
-                // The propagation exception status will be reported into the propagation task execution.
-                LOG.error("Could not propagate {} {}", attrUtil.getType(), delta.getUid().getUidValue(), e);
-                output = e;
-                resultStatus = Result.FAILURE;
-            } catch (Exception e) {
-                result.setStatus(SyncResult.Status.FAILURE);
-                result.setMessage(e.getMessage());
-                LOG.error("Could not update {} {}", attrUtil.getType(), delta.getUid().getUidValue(), e);
-                output = e;
-                resultStatus = Result.FAILURE;
-            }
-            updResults.add(result);
-
-            if (!dryRun) {
-                notificationManager.createTasks(
-                        AuditElements.EventCategoryType.SYNCHRONIZATION,
-                        attrUtil.getType().name().toLowerCase(),
-                        syncTask.getResource().getName(),
-                        "update",
-                        resultStatus,
-                        before,
-                        output,
-                        delta);
-
-                auditManager.audit(
-                        AuditElements.EventCategoryType.SYNCHRONIZATION,
-                        attrUtil.getType().name().toLowerCase(),
-                        syncTask.getResource().getName(),
-                        "update",
-                        resultStatus,
-                        before,
-                        output,
-                        delta);
-            }
-
-            LOG.debug("{} {} successfully updated", attrUtil.getType(), id);
-        }
-
-        return updResults;
-    }
-
-    protected List<SyncResult> delete(SyncDelta delta, final List<Long> subjects, final AttributableUtil attrUtil,
-            final boolean dryRun)
-            throws JobExecutionException {
-
-        if (!syncTask.isPerformDelete()) {
-            LOG.debug("SyncTask not configured for delete");
-            return Collections.<SyncResult>emptyList();
-        }
-
-        LOG.debug("About to delete {}", subjects);
-
-        List<SyncResult> delResults = new ArrayList<SyncResult>();
-
-        for (Long id : subjects) {
-            Object output = null;
-            Result resultStatus = Result.FAILURE;
-
-            try {
-                AbstractAttributableTO subjectTO = AttributableType.USER == attrUtil.getType()
-                        ? userDataBinder.getUserTO(id)
-                        : roleDataBinder.getRoleTO(id);
-                delta = actions.beforeDelete(this, delta, subjectTO);
-
-                final SyncResult result = new SyncResult();
-                result.setId(id);
-                if (subjectTO instanceof UserTO) {
-                    result.setName(((UserTO) subjectTO).getUsername());
-                }
-                if (subjectTO instanceof RoleTO) {
-                    result.setName(((RoleTO) subjectTO).getName());
-                }
-                result.setOperation(ResourceOperation.DELETE);
-                result.setSubjectType(attrUtil.getType());
-                result.setStatus(SyncResult.Status.SUCCESS);
-
-                if (!dryRun) {
-                    try {
-                        List<PropagationTask> tasks = Collections.<PropagationTask>emptyList();
-                        if (AttributableType.USER == attrUtil.getType()) {
-                            tasks = propagationManager.getUserDeleteTaskIds(id, syncTask.getResource().getName());
-                        } else if (AttributableType.ROLE == attrUtil.getType()) {
-                            tasks = propagationManager.getRoleDeleteTaskIds(id, syncTask.getResource().getName());
-                        }
-                        taskExecutor.execute(tasks);
-                    } catch (Exception e) {
-                        // A propagation failure doesn't imply a synchronization failure.
-                        // The propagation exception status will be reported into the propagation task execution.
-                        LOG.error("Could not propagate user " + id, e);
-                    }
-
-                    try {
-                        if (AttributableType.USER == attrUtil.getType()) {
-                            uwfAdapter.delete(id);
-                        } else if (AttributableType.ROLE == attrUtil.getType()) {
-                            rwfAdapter.delete(id);
-                        }
-                        output = null;
-                        resultStatus = Result.SUCCESS;
-                    } catch (Exception e) {
-                        result.setStatus(SyncResult.Status.FAILURE);
-                        result.setMessage(e.getMessage());
-                        LOG.error("Could not delete {} {}", attrUtil.getType(), id, e);
-                        output = e;
-                    }
-                }
-
-                actions.after(this, delta, subjectTO, result);
-                delResults.add(result);
-
-            } catch (NotFoundException e) {
-                LOG.error("Could not find {} {}", attrUtil.getType(), id, e);
-            } catch (UnauthorizedRoleException e) {
-                LOG.error("Not allowed to read {} {}", attrUtil.getType(), id, e);
-            }
-
-            if (!dryRun) {
-                notificationManager.createTasks(
-                        AuditElements.EventCategoryType.SYNCHRONIZATION,
-                        attrUtil.getType().name().toLowerCase(),
-                        syncTask.getResource().getName(),
-                        "delete",
-                        resultStatus,
-                        null, // searching for before object is too much expensive ... 
-                        output,
-                        delta);
-
-                auditManager.audit(
-                        AuditElements.EventCategoryType.SYNCHRONIZATION,
-                        attrUtil.getType().name().toLowerCase(),
-                        syncTask.getResource().getName(),
-                        "delete",
-                        resultStatus,
-                        null, // searching for before object is too much expensive ... 
-                        output,
-                        delta);
-            }
-        }
-
-        return delResults;
-    }
-
-    /**
-     * Look into SyncDelta and take necessary actions (create / update / delete) on user(s).
-     *
-     * @param delta returned by the underlying connector
-     * @throws JobExecutionException in case of synchronization failure.
-     */
-    protected final void doHandle(final SyncDelta delta)
-            throws JobExecutionException {
-
-        if (results == null) {
-            results = new ArrayList<SyncResult>();
-        }
-
-        LOG.debug("Process {} for {} as {}",
-                delta.getDeltaType(), delta.getUid().getUidValue(), delta.getObject().getObjectClass());
-
-        AttributableUtil attrUtil = AttributableUtil.getInstance(delta.getObject().getObjectClass());
-
-        final String uid = delta.getPreviousUid() == null
-                ? delta.getUid().getUidValue()
-                : delta.getPreviousUid().getUidValue();
-        final List<Long> subjectIds = findExisting(uid, delta.getObject(), attrUtil);
-
-        if (SyncDeltaType.CREATE_OR_UPDATE == delta.getDeltaType()) {
-            if (subjectIds.isEmpty()) {
-                results.addAll(create(delta, attrUtil, dryRun));
-            } else if (subjectIds.size() == 1) {
-                results.addAll(update(delta, subjectIds.subList(0, 1), attrUtil, dryRun));
-            } else {
-                switch (resAct) {
-                    case IGNORE:
-                        LOG.error("More than one match {}", subjectIds);
-                        break;
-
-                    case FIRSTMATCH:
-                        results.addAll(update(delta, subjectIds.subList(0, 1), attrUtil, dryRun));
-                        break;
-
-                    case LASTMATCH:
-                        results.addAll(update(delta, subjectIds.subList(subjectIds.size() - 1, subjectIds.size()),
-                                attrUtil, dryRun));
-                        break;
-
-                    case ALL:
-                        results.addAll(update(delta, subjectIds, attrUtil, dryRun));
-                        break;
-
-                    default:
-                }
-            }
-        } else if (SyncDeltaType.DELETE == delta.getDeltaType()) {
-            if (subjectIds.isEmpty()) {
-                LOG.debug("No match found for deletion");
-            } else if (subjectIds.size() == 1) {
-                results.addAll(delete(delta, subjectIds, attrUtil, dryRun));
-            } else {
-                switch (resAct) {
-                    case IGNORE:
-                        LOG.error("More than one match {}", subjectIds);
-                        break;
-
-                    case FIRSTMATCH:
-                        results.addAll(delete(delta, subjectIds.subList(0, 1), attrUtil, dryRun));
-                        break;
-
-                    case LASTMATCH:
-                        results.addAll(delete(delta, subjectIds.subList(subjectIds.size() - 1, subjectIds.size()),
-                                attrUtil,
-                                dryRun));
-                        break;
-
-                    case ALL:
-                        results.addAll(delete(delta, subjectIds, attrUtil, dryRun));
-                        break;
-
-                    default:
-                }
-            }
+        } catch (TimeoutException toe) {
+            LOG.debug("Request timeout", toe);
+            throw toe;
+        } catch (RuntimeException ignore) {
+            LOG.debug("While resolving {}", accountId, ignore);
         }
+        return obj;
     }
 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java?rev=1556227&r1=1556226&r2=1556227&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java Tue Jan  7 14:33:44 2014
@@ -20,7 +20,6 @@ package org.apache.syncope.core.sync.imp
 
 import java.util.AbstractMap;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -40,7 +39,6 @@ import org.apache.syncope.common.to.User
 import org.apache.syncope.common.types.AttributableType;
 import org.apache.syncope.common.types.AuditElements;
 import org.apache.syncope.common.types.AuditElements.Result;
-import org.apache.syncope.common.types.ConflictResolutionAction;
 import org.apache.syncope.common.types.MappingPurpose;
 import org.apache.syncope.common.types.ResourceOperation;
 import org.apache.syncope.common.types.SyncPolicySpec;
@@ -53,7 +51,6 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.beans.AbstractNormalSchema;
 import org.apache.syncope.core.persistence.beans.PropagationTask;
 import org.apache.syncope.core.persistence.beans.SyncPolicy;
-import org.apache.syncope.core.persistence.beans.SyncTask;
 import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
 import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
 import org.apache.syncope.core.persistence.dao.AttributableSearchDAO;
@@ -68,13 +65,11 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.propagation.PropagationByResource;
 import org.apache.syncope.core.propagation.PropagationException;
 import org.apache.syncope.core.propagation.PropagationTaskExecutor;
-import org.apache.syncope.core.propagation.Connector;
 import org.apache.syncope.core.propagation.impl.PropagationManager;
 import org.apache.syncope.core.rest.controller.UnauthorizedRoleException;
 import org.apache.syncope.core.rest.data.AttributableTransformer;
 import org.apache.syncope.core.rest.data.RoleDataBinder;
 import org.apache.syncope.core.rest.data.UserDataBinder;
-import org.apache.syncope.core.sync.SyncActions;
 import org.apache.syncope.core.sync.SyncResult;
 import org.apache.syncope.core.sync.SyncCorrelationRule;
 import org.apache.syncope.core.util.AttributableUtil;
@@ -90,19 +85,11 @@ import org.identityconnectors.framework.
 import org.identityconnectors.framework.common.objects.OperationalAttributes;
 import org.identityconnectors.framework.common.objects.SyncDelta;
 import org.identityconnectors.framework.common.objects.SyncDeltaType;
-import org.identityconnectors.framework.common.objects.SyncResultsHandler;
 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;
 
-public class SyncopeSyncResultHandler implements SyncResultsHandler {
-
-    /**
-     * Logger.
-     */
-    protected static final Logger LOG = LoggerFactory.getLogger(SyncopeSyncResultHandler.class);
+public class SyncopeSyncResultHandler extends AbstractSyncopeSyncResultHandler {
 
     /**
      * Policy DAO.
@@ -197,74 +184,8 @@ public class SyncopeSyncResultHandler im
     @Autowired
     protected AttributableTransformer attrTransformer;
 
-    /**
-     * Syncing connector.
-     */
-    protected Connector connector;
-
-    /**
-     * SyncJob actions.
-     */
-    protected SyncActions actions;
-
-    protected Collection<SyncResult> results;
-
-    protected SyncTask syncTask;
-
-    protected ConflictResolutionAction resAct;
-
-    protected boolean dryRun;
-
     protected Map<Long, String> roleOwnerMap = new HashMap<Long, String>();
 
-    public Connector getConnector() {
-        return connector;
-    }
-
-    public void setConnector(final Connector connector) {
-        this.connector = connector;
-    }
-
-    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;
-    }
-
     public Map<Long, String> getRoleOwnerMap() {
         return roleOwnerMap;
     }
@@ -472,7 +393,7 @@ public class SyncopeSyncResultHandler im
 
         final List<ConnectorObject> found = connector.search(objectClass,
                 new EqualsFilter(new Name(name)), connector.getOperationOptions(
-                        attrUtil.getMappingItems(syncTask.getResource(), MappingPurpose.SYNCHRONIZATION)));
+                attrUtil.getMappingItems(syncTask.getResource(), MappingPurpose.SYNCHRONIZATION)));
 
         if (found.isEmpty()) {
             LOG.debug("No {} found on {} with __NAME__ {}", objectClass, syncTask.getResource(), name);

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java?rev=1556227&r1=1556226&r2=1556227&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java Tue Jan  7 14:33:44 2014
@@ -30,8 +30,10 @@ import org.apache.commons.jexl2.JexlCont
 import org.apache.commons.jexl2.MapContext;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.mod.AttributeMod;
+import org.apache.syncope.common.types.AttributableType;
 import org.apache.syncope.common.types.IntMappingType;
 import org.apache.syncope.common.types.AttributeSchemaType;
+import org.apache.syncope.common.types.MappingPurpose;
 import org.apache.syncope.core.connid.ConnObjectUtil;
 import org.apache.syncope.core.connid.PasswordGenerator;
 import org.apache.syncope.core.persistence.beans.AbstractAttr;
@@ -61,7 +63,9 @@ import org.apache.syncope.core.persisten
 import org.identityconnectors.framework.common.FrameworkUtil;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeBuilder;
+import org.identityconnectors.framework.common.objects.AttributeUtil;
 import org.identityconnectors.framework.common.objects.Name;
+import org.identityconnectors.framework.common.objects.OperationalAttributes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.context.ConfigurableApplicationContext;
@@ -116,6 +120,89 @@ public final class MappingUtil {
     }
 
     /**
+     * Prepare attributes for sending to a connector instance.
+     *
+     * @param <T> user / role
+     * @param attrUtil user / role
+     * @param subject given user / role
+     * @param password clear-text password
+     * @param changePwd whether password should be included for propagation attributes or not
+     * @param vAttrsToBeRemoved virtual attributes to be removed
+     * @param vAttrsToBeUpdated virtual attributes to be added
+     * @param enable whether user must be enabled or not
+     * @param resource target resource
+     * @return account link + prepared attributes
+     */
+    public static <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> prepareAttributes(
+            final AttributableUtil attrUtil, final T subject, final String password, final boolean changePwd,
+            final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated,
+            final Boolean enable, final ExternalResource resource) {
+
+        LOG.debug("Preparing resource attributes for {} on resource {} with attributes {}",
+                subject, resource, subject.getAttrs());
+
+        final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
+        final VirAttrCache virAttrCache = context.getBean(VirAttrCache.class);
+        final PasswordGenerator passwordGenerator = context.getBean(PasswordGenerator.class);
+
+        Set<Attribute> attributes = new HashSet<Attribute>();
+        String accountId = null;
+
+        for (AbstractMappingItem mapping : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+            LOG.debug("Processing schema {}", mapping.getIntAttrName());
+
+            try {
+                if ((attrUtil.getType() == AttributableType.USER
+                        && mapping.getIntMappingType() == IntMappingType.UserVirtualSchema)
+                        || (attrUtil.getType() == AttributableType.ROLE
+                        && mapping.getIntMappingType() == IntMappingType.RoleVirtualSchema)) {
+
+                    LOG.debug("Expire entry cache {}-{}", subject.getId(), mapping.getIntAttrName());
+                    virAttrCache.expire(attrUtil.getType(), subject.getId(), mapping.getIntAttrName());
+                }
+
+                Map.Entry<String, Attribute> preparedAttribute = prepareAttribute(
+                        resource, mapping, subject, password, passwordGenerator, vAttrsToBeRemoved, vAttrsToBeUpdated);
+
+                if (preparedAttribute != null && preparedAttribute.getKey() != null) {
+                    accountId = preparedAttribute.getKey();
+                }
+
+                if (preparedAttribute != null && preparedAttribute.getValue() != null) {
+                    Attribute alreadyAdded = AttributeUtil.find(preparedAttribute.getValue().getName(), attributes);
+
+                    if (alreadyAdded == null) {
+                        attributes.add(preparedAttribute.getValue());
+                    } else {
+                        attributes.remove(alreadyAdded);
+
+                        Set<Object> values = new HashSet<Object>(alreadyAdded.getValue());
+                        values.addAll(preparedAttribute.getValue().getValue());
+
+                        attributes.add(AttributeBuilder.build(preparedAttribute.getValue().getName(), values));
+                    }
+                }
+            } catch (Exception e) {
+                LOG.debug("Attribute '{}' processing failed", mapping.getIntAttrName(), e);
+            }
+        }
+
+        attributes.add(MappingUtil.evaluateNAME(subject, resource, accountId));
+
+        if (enable != null) {
+            attributes.add(AttributeBuilder.buildEnabled(enable));
+        }
+        if (!changePwd) {
+            Attribute pwdAttr = AttributeUtil.find(OperationalAttributes.PASSWORD_NAME, attributes);
+            if (pwdAttr != null) {
+                attributes.remove(pwdAttr);
+            }
+        }
+
+        return new AbstractMap.SimpleEntry<String, Set<Attribute>>(accountId, attributes);
+    }
+
+    /**
      * Prepare an attribute to be sent to a connector instance.
      *
      * @param resource target resource
@@ -129,7 +216,7 @@ public final class MappingUtil {
      * @return account link + prepared attribute
      */
     @SuppressWarnings("unchecked")
-    public static <T extends AbstractAttributable> Map.Entry<String, Attribute> prepareAttribute(
+    private static <T extends AbstractAttributable> Map.Entry<String, Attribute> prepareAttribute(
             final ExternalResource resource, final AbstractMappingItem mapItem,
             final T subject, final String password, final PasswordGenerator passwordGenerator,
             final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated) {
@@ -250,16 +337,19 @@ public final class MappingUtil {
                 if (passwordAttrValue == null) {
                     result = null;
                 } else {
-                    result = new AbstractMap.SimpleEntry<String, Attribute>(null,
+                    result = new AbstractMap.SimpleEntry<String, Attribute>(
+                            null,
                             AttributeBuilder.buildPassword(passwordAttrValue.toCharArray()));
                 }
             } else {
                 if ((schema != null && schema.isMultivalue()) || AttributableUtil.getInstance(subject).getType()
                         != mapItem.getIntMappingType().getAttributableType()) {
-                    result = new AbstractMap.SimpleEntry<String, Attribute>(null, AttributeBuilder.build(extAttrName,
-                            objValues));
+                    result = new AbstractMap.SimpleEntry<String, Attribute>(
+                            null,
+                            AttributeBuilder.build(extAttrName, objValues));
                 } else {
-                    result = new AbstractMap.SimpleEntry<String, Attribute>(null, objValues.isEmpty()
+                    result = new AbstractMap.SimpleEntry<String, Attribute>(
+                            null, objValues.isEmpty()
                             ? AttributeBuilder.build(extAttrName)
                             : AttributeBuilder.build(extAttrName, objValues.iterator().next()));
                 }
@@ -378,13 +468,6 @@ public final class MappingUtil {
                 for (AbstractAttributable attributable : attributables) {
                     AbstractVirAttr virAttr = attributable.getVirAttr(mappingItem.getIntAttrName());
                     if (virAttr != null) {
-                        if (virAttr.getValues() != null) {
-                            for (String value : virAttr.getValues()) {
-                                attrValue = new UAttrValue();
-                                attrValue.setStringValue(value);
-                                values.add(attrValue);
-                            }
-                        }
                         if (vAttrsToBeRemoved != null && vAttrsToBeUpdated != null) {
                             if (vAttrsToBeUpdated.containsKey(mappingItem.getIntAttrName())) {
                                 virAttr.setValues(
@@ -396,6 +479,13 @@ public final class MappingUtil {
                                         + mappingItem.getIntAttrName() + "'");
                             }
                         }
+                        if (virAttr.getValues() != null) {
+                            for (String value : virAttr.getValues()) {
+                                attrValue = new UAttrValue();
+                                attrValue.setStringValue(value);
+                                values.add(attrValue);
+                            }
+                        }
                     }
 
                     LOG.debug("Retrieved virtual attribute {}"

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/TaskUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/TaskUtil.java?rev=1556227&r1=1556226&r2=1556227&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/util/TaskUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/TaskUtil.java Tue Jan  7 14:33:44 2014
@@ -23,9 +23,11 @@ import org.apache.syncope.common.to.Prop
 import org.apache.syncope.common.to.SchedTaskTO;
 import org.apache.syncope.common.to.SyncTaskTO;
 import org.apache.syncope.common.to.AbstractTaskTO;
+import org.apache.syncope.common.to.PushTaskTO;
 import org.apache.syncope.common.types.TaskType;
 import org.apache.syncope.core.persistence.beans.NotificationTask;
 import org.apache.syncope.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.persistence.beans.PushTask;
 import org.apache.syncope.core.persistence.beans.SchedTask;
 import org.apache.syncope.core.persistence.beans.SyncTask;
 import org.apache.syncope.core.persistence.beans.Task;
@@ -43,6 +45,8 @@ public final class TaskUtil {
         TaskType type;
         if (task instanceof SyncTask) {
             type = TaskType.SYNCHRONIZATION;
+        } else if (task instanceof PushTask) {
+            type = TaskType.PUSH;
         } else if (task instanceof SchedTask) {
             type = TaskType.SCHEDULED;
         } else if (task instanceof PropagationTask) {
@@ -66,6 +70,8 @@ public final class TaskUtil {
             type = TaskType.SCHEDULED;
         } else if (taskClass == SyncTaskTO.class) {
             type = TaskType.SYNCHRONIZATION;
+        } else if (taskClass == PushTaskTO.class) {
+            type = TaskType.PUSH;
         } else {
             throw new IllegalArgumentException("Invalid TaskTO class: " + taskClass.getName());
         }
@@ -101,6 +107,10 @@ public final class TaskUtil {
                 result = (Class<T>) SyncTask.class;
                 break;
 
+            case PUSH:
+                result = (Class<T>) PushTask.class;
+                break;
+
             case NOTIFICATION:
                 result = (Class<T>) NotificationTask.class;
                 break;
@@ -112,29 +122,12 @@ public final class TaskUtil {
     }
 
     public <T extends Task> T newTask() {
-        T result = null;
-
-        switch (type) {
-            case PROPAGATION:
-                result = (T) new PropagationTask();
-                break;
-
-            case SCHEDULED:
-                result = (T) new SchedTask();
-                break;
-
-            case SYNCHRONIZATION:
-                result = (T) new SyncTask();
-                break;
-
-            case NOTIFICATION:
-                result = (T) new NotificationTask();
-                break;
-
-            default:
+        final Class<T> taskClass = taskClass();
+        try {
+            return taskClass == null ? null : taskClass.newInstance();
+        } catch (Exception e) {
+            return null;
         }
-
-        return result;
     }
 
     public <T extends AbstractTaskTO> Class<T> taskTOClass() {
@@ -153,6 +146,10 @@ public final class TaskUtil {
                 result = (Class<T>) SyncTaskTO.class;
                 break;
 
+            case PUSH:
+                result = (Class<T>) PushTaskTO.class;
+                break;
+
             case NOTIFICATION:
                 result = (Class<T>) NotificationTaskTO.class;
                 break;
@@ -163,29 +160,13 @@ public final class TaskUtil {
         return result;
     }
 
+    @SuppressWarnings("unchecked")
     public <T extends AbstractTaskTO> T newTaskTO() {
-        T result = null;
-
-        switch (type) {
-            case PROPAGATION:
-                result = (T) new PropagationTaskTO();
-                break;
-
-            case SCHEDULED:
-                result = (T) new SchedTaskTO();
-                break;
-
-            case SYNCHRONIZATION:
-                result = (T) new SyncTaskTO();
-                break;
-
-            case NOTIFICATION:
-                result = (T) new NotificationTaskTO();
-                break;
-
-            default:
+        final Class<T> taskClass = taskTOClass();
+        try {
+            return taskClass == null ? null : taskClass.newInstance();
+        } catch (Exception e) {
+            return null;
         }
-
-        return result;
     }
 }

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=1556227&r1=1556226&r2=1556227&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 Tue Jan  7 14:33:44 2014
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.rest;
 
+import static org.apache.syncope.core.rest.AbstractTest.taskService;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -54,6 +55,7 @@ import org.apache.syncope.common.types.P
 import org.apache.syncope.common.types.TaskType;
 import org.apache.syncope.common.types.TraceLevel;
 import org.apache.syncope.common.SyncopeClientException;
+import org.apache.syncope.common.to.PushTaskTO;
 import org.apache.syncope.core.sync.TestSyncActions;
 import org.apache.syncope.core.sync.TestSyncRule;
 import org.apache.syncope.core.sync.impl.SyncJob;
@@ -692,8 +694,7 @@ public class TaskTestITCase extends Abst
         assertEquals("updatedSYNCOPE230@syncope.apache.org", email);
     }
 
-    private TaskExecTO execSyncTask(final Long taskId, final int maxWaitSeconds,
-            final boolean dryRun) {
+    private TaskExecTO execSyncTask(final Long taskId, final int maxWaitSeconds, final boolean dryRun) {
 
         AbstractTaskTO taskTO = taskService.read(taskId);
         assertNotNull(taskTO);
@@ -910,4 +911,20 @@ public class TaskTestITCase extends Abst
 
         assertFalse(taskService.list(TaskType.PROPAGATION).getResult().containsAll(after));
     }
+
+    @Test
+    public void pushUsers() {
+        // Read sync task
+        PushTaskTO task = taskService.<PushTaskTO>read(13L);
+        assertNotNull(task);
+
+        execSyncTask(task.getId(), 50, false);
+
+        final JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
+
+        assertEquals("vivaldi", jdbcTemplate.queryForObject("SELECT ID FROM test2 WHERE ID=?", String.class, "vivaldi"));
+        assertEquals("bellini", jdbcTemplate.queryForObject("SELECT ID FROM test2 WHERE ID=?", String.class, "bellini"));
+        assertEquals("rossini", jdbcTemplate.queryForObject("SELECT ID FROM test2 WHERE ID=?", String.class, "rossini"));
+        assertEquals("puccini", jdbcTemplate.queryForObject("SELECT ID FROM test2 WHERE ID=?", String.class, "puccini"));
+    }
 }

Modified: syncope/trunk/core/src/test/java/org/apache/syncope/core/sync/TestSyncActions.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/test/java/org/apache/syncope/core/sync/TestSyncActions.java?rev=1556227&r1=1556226&r2=1556227&view=diff
==============================================================================
--- syncope/trunk/core/src/test/java/org/apache/syncope/core/sync/TestSyncActions.java (original)
+++ syncope/trunk/core/src/test/java/org/apache/syncope/core/sync/TestSyncActions.java Tue Jan  7 14:33:44 2014
@@ -22,8 +22,8 @@ import org.apache.syncope.common.mod.Abs
 import org.apache.syncope.common.mod.AttributeMod;
 import org.apache.syncope.common.to.AbstractAttributableTO;
 import org.apache.syncope.common.to.AttributeTO;
+import org.apache.syncope.core.sync.impl.AbstractSyncopeSyncResultHandler;
 import org.identityconnectors.framework.common.objects.SyncDelta;
-import org.identityconnectors.framework.common.objects.SyncResultsHandler;
 import org.quartz.JobExecutionException;
 
 public class TestSyncActions extends DefaultSyncActions {
@@ -31,7 +31,7 @@ public class TestSyncActions extends Def
     private int counter = 0;
 
     @Override
-    public <T extends AbstractAttributableTO> SyncDelta beforeCreate(final SyncResultsHandler handler,
+    public <T extends AbstractAttributableTO> SyncDelta beforeCreate(final AbstractSyncopeSyncResultHandler handler,
             final SyncDelta delta, final T subject) throws JobExecutionException {
 
         AttributeTO attrTO = null;
@@ -53,7 +53,7 @@ public class TestSyncActions extends Def
 
     @Override
     public <T extends AbstractAttributableTO, K extends AbstractAttributableMod> SyncDelta beforeUpdate(
-            final SyncResultsHandler handler, final SyncDelta delta, final T subject, final K subjectMod)
+            final AbstractSyncopeSyncResultHandler handler, final SyncDelta delta, final T subject, final K subjectMod)
             throws JobExecutionException {
 
         subjectMod.getAttrsToRemove().add("fullname");

Modified: syncope/trunk/core/src/test/resources/content.xml
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/test/resources/content.xml?rev=1556227&r1=1556226&r2=1556227&view=diff
==============================================================================
--- syncope/trunk/core/src/test/resources/content.xml (original)
+++ syncope/trunk/core/src/test/resources/content.xml Tue Jan  7 14:33:44 2014
@@ -512,7 +512,7 @@ under the License.
                     creator="admin" lastModifier="admin" 
                     creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
   <ExternalResource name="resource-testdb2" connector_id="106"
-                    randomPwdIfNotProvided="0" enforceMandatoryCondition="1" propagationMode="ONE_PHASE"
+                    randomPwdIfNotProvided="1" enforceMandatoryCondition="1" propagationMode="ONE_PHASE"
                     propagationPriority="0" propagationPrimary="0" createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" syncTraceLevel="ALL"
                     creator="admin" lastModifier="admin" 
                     creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
@@ -839,7 +839,10 @@ under the License.
         jobClassName="org.apache.syncope.core.sync.impl.SyncJob"/>
   <Task DTYPE="SyncTask" id="12" name="VirAttrCache test" resource_name="resource-csv"
         performCreate="0" performUpdate="1" performDelete="0" syncStatus="0" fullReconciliation="1"
-        jobClassName="org.apache.syncope.core.sync.impl.SyncJob"/>        
+        jobClassName="org.apache.syncope.core.sync.impl.SyncJob"/>
+  <Task DTYPE="PushTask" id="13" name="Export on resource-testdb" resource_name="resource-testdb2"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"
+        jobClassName="org.apache.syncope.core.sync.impl.PushJob"/>
       
   <Notification id="1" sender="test@syncope.apache.org" subject="Test subject" template="test" selfAsRecipient="0" traceLevel="ALL"
                 about="fullname==*o*;fullname==*i*"