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/06/11 10:16:41 UTC

svn commit: r1601824 - in /syncope/trunk: common/src/main/java/org/apache/syncope/common/to/ common/src/main/java/org/apache/syncope/common/types/ core/src/main/java/org/apache/syncope/core/persistence/beans/ core/src/main/java/org/apache/syncope/core/...

Author: fmartelli
Date: Wed Jun 11 08:16:40 2014
New Revision: 1601824

URL: http://svn.apache.org/r1601824
Log:
[SYNCOPE-471] Provides matching rule management for push and sync actions. Still missing for more integration tests.

Added:
    syncope/trunk/common/src/main/java/org/apache/syncope/common/types/MatchingRule.java
    syncope/trunk/common/src/main/java/org/apache/syncope/common/types/UnmatchingRule.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractAttributableController.java
Modified:
    syncope/trunk/common/src/main/java/org/apache/syncope/common/to/AbstractSyncTaskTO.java
    syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractSyncTask.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/PushTask.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/SyncTask.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/AbstractSyncActions.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/DefaultPushActions.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/PushActions.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncActions.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/AbstractSyncopeResultHandler.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java
    syncope/trunk/core/src/test/java/org/apache/syncope/core/persistence/relationships/TaskTest.java
    syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/TaskTestITCase.java

Modified: syncope/trunk/common/src/main/java/org/apache/syncope/common/to/AbstractSyncTaskTO.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/to/AbstractSyncTaskTO.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/to/AbstractSyncTaskTO.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/to/AbstractSyncTaskTO.java Wed Jun 11 08:16:40 2014
@@ -21,6 +21,8 @@ package org.apache.syncope.common.to;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.types.MatchingRule;
+import org.apache.syncope.common.types.UnmatchingRule;
 
 @XmlRootElement(name = "abstractSyncTask")
 @XmlType
@@ -41,6 +43,10 @@ public class AbstractSyncTaskTO extends 
 
     private String actionsClassName;
 
+    private UnmatchingRule unmatchigRule;
+
+    private MatchingRule matchigRule;
+
     public String getResource() {
         return resource;
     }
@@ -88,4 +94,20 @@ public class AbstractSyncTaskTO extends 
     public void setActionsClassName(final String actionsClassName) {
         this.actionsClassName = actionsClassName;
     }
+
+    public UnmatchingRule getUnmatchigRule() {
+        return unmatchigRule;
+    }
+
+    public void setUnmatchigRule(final UnmatchingRule unmatchigRule) {
+        this.unmatchigRule = unmatchigRule;
+    }
+
+    public MatchingRule getMatchigRule() {
+        return matchigRule;
+    }
+
+    public void setMatchigRule(final MatchingRule matchigRule) {
+        this.matchigRule = matchigRule;
+    }
 }

Added: syncope/trunk/common/src/main/java/org/apache/syncope/common/types/MatchingRule.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/types/MatchingRule.java?rev=1601824&view=auto
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/types/MatchingRule.java (added)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/types/MatchingRule.java Wed Jun 11 08:16:40 2014
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.types;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+/**
+ * Sync/Push task matching rule.
+ */
+@XmlEnum
+public enum MatchingRule {
+
+    /**
+     * Do not perform any action.
+     */
+    IGNORE,
+    /**
+     * Update matching entity.
+     */
+    UPDATE,
+    /**
+     * Delete resource entity.
+     */
+    DEPROVISION,
+    /**
+     * Unlink resource and delete resource entity.
+     */
+    UNASSIGN,
+    /**
+     * Just unlink resource without performing any (de-)provisioning operation.
+     */
+    UNLINK,
+    /**
+     * Just link resource without performing any (de-)provisioning operation.
+     */
+    LINK
+
+}

Modified: syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java Wed Jun 11 08:16:40 2014
@@ -25,6 +25,7 @@ public enum ResourceOperation {
 
     CREATE,
     UPDATE,
-    DELETE
+    DELETE,
+    NONE
 
 }

Added: syncope/trunk/common/src/main/java/org/apache/syncope/common/types/UnmatchingRule.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/types/UnmatchingRule.java?rev=1601824&view=auto
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/types/UnmatchingRule.java (added)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/types/UnmatchingRule.java Wed Jun 11 08:16:40 2014
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.types;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+/**
+ * Sync/Push task un-matching rule.
+ */
+@XmlEnum
+public enum UnmatchingRule {
+
+    /**
+     * Do not perform any action.
+     */
+    IGNORE,
+    /**
+     * Link the resource and create entity.
+     */
+    ASSIGN,
+    /**
+     * Create entity without linking the resource.
+     */
+    PROVISION,
+    /**
+     * Just unlink resource without performing any (de-)provisioning operation.
+     * In case of sync task UNLINK and IGNORE will coincide.
+     */
+    UNLINK
+
+}

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractSyncTask.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractSyncTask.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractSyncTask.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractSyncTask.java Wed Jun 11 08:16:40 2014
@@ -19,10 +19,14 @@
 package org.apache.syncope.core.persistence.beans;
 
 import javax.persistence.Basic;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
 import javax.persistence.ManyToOne;
 import javax.persistence.MappedSuperclass;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
+import org.apache.syncope.common.types.MatchingRule;
+import org.apache.syncope.common.types.UnmatchingRule;
 import org.apache.syncope.core.persistence.validation.entity.SyncTaskCheck;
 
 @MappedSuperclass
@@ -59,6 +63,18 @@ public abstract class AbstractSyncTask e
 
     private String actionsClassName;
 
+    /**
+     * @see UnmatchingRule
+     */
+    @Enumerated(EnumType.STRING)
+    protected UnmatchingRule unmatchigRule;
+
+    /**
+     * @see MatchingRule
+     */
+    @Enumerated(EnumType.STRING)
+    protected MatchingRule matchigRule;
+
     public AbstractSyncTask(final String jobClassName) {
         super();
         super.setJobClassName(jobClassName);
@@ -116,4 +132,16 @@ public abstract class AbstractSyncTask e
     public void setActionsClassName(final String actionsClassName) {
         this.actionsClassName = actionsClassName;
     }
+
+    public abstract UnmatchingRule getUnmatchigRule();
+
+    public void setUnmatchigRule(final UnmatchingRule unmatchigRule) {
+        this.unmatchigRule = unmatchigRule;
+    }
+
+    public abstract MatchingRule getMatchigRule();
+
+    public void setMatchigRule(final MatchingRule matchigRule) {
+        this.matchigRule = matchigRule;
+    }
 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/PushTask.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/PushTask.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/PushTask.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/PushTask.java Wed Jun 11 08:16:40 2014
@@ -19,12 +19,21 @@
 package org.apache.syncope.core.persistence.beans;
 
 import javax.persistence.Entity;
+import javax.persistence.Transient;
+import org.apache.syncope.common.types.MatchingRule;
+import org.apache.syncope.common.types.UnmatchingRule;
 
 @Entity
 public class PushTask extends AbstractSyncTask {
 
     private static final long serialVersionUID = -4141057723006682564L;
 
+    @Transient
+    private static UnmatchingRule DEF_UNMATCHIG_RULE = UnmatchingRule.ASSIGN;
+
+    @Transient
+    private static MatchingRule DEF_MATCHIG_RULE = MatchingRule.UPDATE;
+
     private String userFilter;
 
     private String roleFilter;
@@ -48,7 +57,17 @@ public class PushTask extends AbstractSy
         return roleFilter;
     }
 
-    public void setRoleFilter(String roleFilter) {
+    public void setRoleFilter(final String roleFilter) {
         this.roleFilter = roleFilter;
     }
+
+    @Override
+    public UnmatchingRule getUnmatchigRule() {
+        return this.unmatchigRule == null ? DEF_UNMATCHIG_RULE : unmatchigRule;
+    }
+
+    @Override
+    public MatchingRule getMatchigRule() {
+        return this.matchigRule == null ? DEF_MATCHIG_RULE : this.matchigRule;
+    }
 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/SyncTask.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/SyncTask.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/SyncTask.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/SyncTask.java Wed Jun 11 08:16:40 2014
@@ -21,10 +21,13 @@ package org.apache.syncope.core.persiste
 import javax.persistence.Basic;
 import javax.persistence.Entity;
 import javax.persistence.Lob;
+import javax.persistence.Transient;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
 import org.apache.syncope.common.to.RoleTO;
 import org.apache.syncope.common.to.UserTO;
+import org.apache.syncope.common.types.MatchingRule;
+import org.apache.syncope.common.types.UnmatchingRule;
 import org.apache.syncope.core.sync.impl.SyncJob;
 import org.apache.syncope.core.util.XMLSerializer;
 
@@ -33,6 +36,12 @@ public class SyncTask extends AbstractSy
 
     private static final long serialVersionUID = -4141057723006682563L;
 
+    @Transient
+    private static UnmatchingRule DEF_UNMATCHIG_RULE = UnmatchingRule.PROVISION;
+
+    @Transient
+    private static MatchingRule DEF_MATCHIG_RULE = MatchingRule.UPDATE;
+
     @Lob
     private String userTemplate;
 
@@ -78,4 +87,14 @@ public class SyncTask extends AbstractSy
     public void setFullReconciliation(final boolean fullReconciliation) {
         this.fullReconciliation = getBooleanAsInteger(fullReconciliation);
     }
+
+    @Override
+    public UnmatchingRule getUnmatchigRule() {
+        return this.unmatchigRule == null ? DEF_UNMATCHIG_RULE : unmatchigRule;
+    }
+
+    @Override
+    public MatchingRule getMatchigRule() {
+        return this.matchigRule == null ? DEF_MATCHIG_RULE : this.matchigRule;
+    }
 }

Added: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractAttributableController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractAttributableController.java?rev=1601824&view=auto
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractAttributableController.java (added)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/AbstractAttributableController.java Wed Jun 11 08:16:40 2014
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.rest.controller;
+
+import java.util.List;
+import org.apache.syncope.common.mod.AbstractAttributableMod;
+import org.apache.syncope.common.to.AbstractAttributableTO;
+import org.apache.syncope.core.persistence.dao.search.OrderByClause;
+import org.apache.syncope.core.persistence.dao.search.SearchCond;
+
+public abstract class AbstractAttributableController<T extends AbstractAttributableTO, V extends AbstractAttributableMod>
+        extends AbstractResourceAssociator<T> {
+
+    public abstract T read(Long id);
+
+    public abstract int count();
+
+    public abstract T create(T attributableTO);
+
+    public abstract T update(V attributableMod);
+
+    public abstract T delete(Long id);
+
+    public abstract List<T> list(int page, int size, List<OrderByClause> orderBy);
+
+    public abstract List<T> search(SearchCond searchCondition, int page, int size, List<OrderByClause> orderBy);
+
+    public abstract int searchCount(SearchCond searchCondition);
+}

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java Wed Jun 11 08:16:40 2014
@@ -66,7 +66,7 @@ import org.springframework.transaction.i
  * @see AbstractTransactionalController
  */
 @Component
-public class RoleController extends AbstractResourceAssociator<RoleTO> {
+public class RoleController extends AbstractAttributableController<RoleTO, RoleMod> {
 
     @Autowired
     protected RoleDAO roleDAO;
@@ -97,6 +97,7 @@ public class RoleController extends Abst
 
     @PreAuthorize("hasAnyRole('ROLE_READ', T(org.apache.syncope.common.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")
     @Transactional(readOnly = true)
+    @Override
     public RoleTO read(final Long roleId) {
         SyncopeRole role;
         // bypass role entitlements check
@@ -177,12 +178,14 @@ public class RoleController extends Abst
 
     @PreAuthorize("isAuthenticated()")
     @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+    @Override
     public int count() {
         return roleDAO.count();
     }
 
     @PreAuthorize("isAuthenticated()")
     @Transactional(readOnly = true)
+    @Override
     public List<RoleTO> list(final int page, final int size, final List<OrderByClause> orderBy) {
         List<SyncopeRole> roles = roleDAO.findAll(page, size, orderBy);
 
@@ -196,6 +199,7 @@ public class RoleController extends Abst
 
     @PreAuthorize("isAuthenticated()")
     @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+    @Override
     public int searchCount(final SearchCond searchCondition) {
         final Set<Long> adminRoleIds = EntitlementUtil.getRoleIds(EntitlementUtil.getOwnedEntitlementNames());
         return searchDAO.count(adminRoleIds, searchCondition, AttributableUtil.getInstance(AttributableType.ROLE));
@@ -203,6 +207,7 @@ public class RoleController extends Abst
 
     @PreAuthorize("isAuthenticated()")
     @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+    @Override
     public List<RoleTO> search(final SearchCond searchCondition, final int page, final int size,
             final List<OrderByClause> orderBy) {
 
@@ -219,6 +224,7 @@ public class RoleController extends Abst
     }
 
     @PreAuthorize("hasRole('ROLE_CREATE')")
+    @Override
     public RoleTO create(final RoleTO roleTO) {
         // Check that this operation is allowed to be performed by caller
         Set<Long> allowedRoleIds = EntitlementUtil.getRoleIds(EntitlementUtil.getOwnedEntitlementNames());
@@ -253,6 +259,7 @@ public class RoleController extends Abst
     }
 
     @PreAuthorize("hasRole('ROLE_UPDATE')")
+    @Override
     public RoleTO update(final RoleMod roleMod) {
         // Check that this operation is allowed to be performed by caller
         binder.getRoleFromId(roleMod.getId());
@@ -282,6 +289,7 @@ public class RoleController extends Abst
     }
 
     @PreAuthorize("hasRole('ROLE_DELETE')")
+    @Override
     public RoleTO delete(final Long roleId) {
         List<SyncopeRole> ownedRoles = roleDAO.findOwnedByRole(roleId);
         if (!ownedRoles.isEmpty()) {

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java Wed Jun 11 08:16:40 2014
@@ -38,7 +38,6 @@ import org.apache.syncope.common.to.User
 import org.apache.syncope.common.types.AttributableType;
 import org.apache.syncope.common.types.ClientExceptionType;
 import org.apache.syncope.common.SyncopeClientException;
-import org.apache.syncope.common.mod.MembershipMod;
 import org.apache.syncope.core.persistence.beans.PropagationTask;
 import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
 import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
@@ -71,7 +70,7 @@ import org.springframework.transaction.i
  * @see AbstractTransactionalController
  */
 @Component
-public class UserController extends AbstractResourceAssociator<UserTO> {
+public class UserController extends AbstractAttributableController<UserTO, UserMod> {
 
     @Autowired
     protected UserDAO userDAO;
@@ -116,12 +115,14 @@ public class UserController extends Abst
 
     @PreAuthorize("hasRole('USER_LIST')")
     @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+    @Override
     public int count() {
         return userDAO.count(EntitlementUtil.getRoleIds(EntitlementUtil.getOwnedEntitlementNames()));
     }
 
     @PreAuthorize("hasRole('USER_LIST')")
     @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+    @Override
     public int searchCount(final SearchCond searchCondition) {
         return searchDAO.count(EntitlementUtil.getRoleIds(EntitlementUtil.getOwnedEntitlementNames()),
                 searchCondition, AttributableUtil.getInstance(AttributableType.USER));
@@ -129,6 +130,7 @@ public class UserController extends Abst
 
     @PreAuthorize("hasRole('USER_LIST')")
     @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+    @Override
     public List<UserTO> list(final int page, final int size, final List<OrderByClause> orderBy) {
         Set<Long> adminRoleIds = EntitlementUtil.getRoleIds(EntitlementUtil.getOwnedEntitlementNames());
 
@@ -150,12 +152,14 @@ public class UserController extends Abst
 
     @PreAuthorize("hasRole('USER_READ')")
     @Transactional(readOnly = true)
+    @Override
     public UserTO read(final Long userId) {
         return binder.getUserTO(userId);
     }
 
     @PreAuthorize("hasRole('USER_LIST')")
     @Transactional(readOnly = true)
+    @Override
     public List<UserTO> search(final SearchCond searchCondition, final int page, final int size,
             final List<OrderByClause> orderBy) {
 
@@ -183,6 +187,7 @@ public class UserController extends Abst
     }
 
     @PreAuthorize("hasRole('USER_CREATE')")
+    @Override
     public UserTO create(final UserTO userTO) {
         Set<Long> requestRoleIds = new HashSet<Long>(userTO.getMemberships().size());
         for (MembershipTO membership : userTO.getMemberships()) {
@@ -236,6 +241,7 @@ public class UserController extends Abst
     }
 
     @PreAuthorize("hasRole('USER_UPDATE')")
+    @Override
     public UserTO update(final UserMod userMod) {
         // AttributableMod transformation (if configured)
         UserMod actual = attrTransformer.transform(userMod);
@@ -332,6 +338,7 @@ public class UserController extends Abst
     }
 
     @PreAuthorize("hasRole('USER_DELETE')")
+    @Override
     public UserTO delete(final Long userId) {
         List<SyncopeRole> ownedRoles = roleDAO.findOwnedByUser(userId);
         if (!ownedRoles.isEmpty()) {

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java Wed Jun 11 08:16:40 2014
@@ -103,6 +103,7 @@ public class TaskDataBinder {
             final PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
 
             pushTask.setUserFilter(pushTaskTO.getUserFilter());
+            pushTask.setRoleFilter(pushTaskTO.getRoleFilter());
 
         } else if (task instanceof SyncTask && taskTO instanceof SyncTaskTO) {
             final SyncTask syncTask = (SyncTask) task;
@@ -152,7 +153,8 @@ public class TaskDataBinder {
         task.setPerformUpdate(taskTO.isPerformUpdate());
         task.setPerformDelete(taskTO.isPerformDelete());
         task.setSyncStatus(taskTO.isSyncStatus());
-
+        task.setMatchigRule(taskTO.getMatchigRule());
+        task.setUnmatchigRule(taskTO.getUnmatchigRule());
         task.setActionsClassName(taskTO.getActionsClassName());
     }
 

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/AbstractSyncActions.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/AbstractSyncActions.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/AbstractSyncActions.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/AbstractSyncActions.java Wed Jun 11 08:16:40 2014
@@ -22,7 +22,7 @@ import java.util.List;
 import org.apache.syncope.core.sync.impl.AbstractSyncopeResultHandler;
 import org.quartz.JobExecutionException;
 
-public interface AbstractSyncActions<T extends AbstractSyncopeResultHandler> {
+public interface AbstractSyncActions<T extends AbstractSyncopeResultHandler<?, ?>> {
 
     /**
      * Action to be executed before to start the synchronization task execution.

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/DefaultPushActions.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/DefaultPushActions.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/DefaultPushActions.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/DefaultPushActions.java Wed Jun 11 08:16:40 2014
@@ -37,7 +37,7 @@ public class DefaultPushActions implemen
     }
 
     @Override
-    public <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeCreate(
+    public <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeAssign(
             final AbstractSyncopeResultHandler<?, ?> handler,
             final Map.Entry<String, Set<Attribute>> delta,
             final T subject) throws JobExecutionException {
@@ -62,6 +62,54 @@ public class DefaultPushActions implemen
     }
 
     @Override
+    public <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeProvision(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException {
+        return delta;
+    }
+
+    @Override
+    public <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeLink(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException {
+        return delta;
+    }
+
+    @Override
+    public <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeUnlink(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException {
+        return delta;
+    }
+
+    @Override
+    public <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeUnassign(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException {
+        return delta;
+    }
+
+    @Override
+    public <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeDeprovision(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException {
+        return delta;
+    }
+
+    @Override
+    public <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeDelete(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException {
+        return delta;
+    }
+
+    @Override
     public void afterAll(
             final AbstractSyncopeResultHandler<?, ?> handler,
             final List<SyncResult> results)

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=1601824&r1=1601823&r2=1601824&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 Wed Jun 11 08:16:40 2014
@@ -73,6 +73,51 @@ public class DefaultSyncActions implemen
     }
 
     @Override
+    public <T extends AbstractAttributableTO> SyncDelta beforeAssign(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final SyncDelta delta,
+            final T subject) throws JobExecutionException {
+
+        return delta;
+    }
+
+    @Override
+    public <T extends AbstractAttributableTO> SyncDelta beforeUnassign(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final SyncDelta delta,
+            final T subject) throws JobExecutionException {
+
+        return delta;
+    }
+
+    @Override
+    public <T extends AbstractAttributableTO> SyncDelta beforeDeprovision(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final SyncDelta delta,
+            final T subject) throws JobExecutionException {
+
+        return delta;
+    }
+
+    @Override
+    public <T extends AbstractAttributableTO> SyncDelta beforeUnlink(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final SyncDelta delta,
+            final T subject) throws JobExecutionException {
+
+        return delta;
+    }
+
+    @Override
+    public <T extends AbstractAttributableTO> SyncDelta beforeLink(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final SyncDelta delta,
+            final T subject) throws JobExecutionException {
+
+        return delta;
+    }
+
+    @Override
     public void afterAll(
             final AbstractSyncopeResultHandler<?, ?> handler,
             final List<SyncResult> results)

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/PushActions.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/PushActions.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/PushActions.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/PushActions.java Wed Jun 11 08:16:40 2014
@@ -31,7 +31,7 @@ import org.quartz.JobExecutionException;
 public interface PushActions extends AbstractSyncActions<AbstractSyncopeResultHandler<?, ?>> {
 
     /**
-     * Action to be executed before to create a synchronized user locally.
+     * Action to be executed before to assign (link & provision) a synchronized user to the resource.
      *
      * @param handler synchronization handler being executed.
      * @param delta info to be pushed out (accountId, attributes).
@@ -39,13 +39,27 @@ public interface PushActions extends Abs
      * @return info to be pushed out (accountId, attributes).
      * @throws JobExecutionException in case of generic failure
      */
-    <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeCreate(
+    <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeAssign(
             final AbstractSyncopeResultHandler<?, ?> handler,
             final Map.Entry<String, Set<Attribute>> delta,
             final T subject) throws JobExecutionException;
 
     /**
-     * Action to be executed before to update a synchronized user locally.
+     * Action to be executed before to provision a synchronized user to the resource.
+     *
+     * @param handler synchronization handler being executed.
+     * @param delta info to be pushed out (accountId, attributes).
+     * @param subject user / role to be created.
+     * @return info to be pushed out (accountId, attributes).
+     * @throws JobExecutionException in case of generic failure
+     */
+    <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeProvision(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException;
+
+    /**
+     * Action to be executed before to update a synchronized user on the resource.
      *
      * @param handler synchronization handler being executed.
      * @param delta info to be pushed out (accountId, attributes).
@@ -59,6 +73,76 @@ public interface PushActions extends Abs
             final T subject) throws JobExecutionException;
 
     /**
+     * Action to be executed before to link a synchronized user to the resource.
+     *
+     * @param handler synchronization handler being executed.
+     * @param delta info to be pushed out (accountId, attributes).
+     * @param subject user / role to be created.
+     * @return info to be pushed out (accountId, attributes).
+     * @throws JobExecutionException in case of generic failure
+     */
+    <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeLink(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException;
+
+    /**
+     * Action to be executed before to unlink a synchronized user from the resource.
+     *
+     * @param handler synchronization handler being executed.
+     * @param delta info to be pushed out (accountId, attributes).
+     * @param subject user / role to be created.
+     * @return info to be pushed out (accountId, attributes).
+     * @throws JobExecutionException in case of generic failure
+     */
+    <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeUnlink(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException;
+
+    /**
+     * Action to be executed before to unassign a synchronized user from the resource.
+     *
+     * @param handler synchronization handler being executed.
+     * @param delta info to be pushed out (accountId, attributes).
+     * @param subject user / role to be created.
+     * @return info to be pushed out (accountId, attributes).
+     * @throws JobExecutionException in case of generic failure
+     */
+    <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeUnassign(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException;
+
+    /**
+     * Action to be executed before to unassign a synchronized user from the resource.
+     *
+     * @param handler synchronization handler being executed.
+     * @param delta info to be pushed out (accountId, attributes).
+     * @param subject user / role to be created.
+     * @return info to be pushed out (accountId, attributes).
+     * @throws JobExecutionException in case of generic failure
+     */
+    <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeDeprovision(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException;
+
+    /**
+     * Action to be executed before delete a synchronized user locally and from the resource.
+     *
+     * @param handler synchronization handler being executed.
+     * @param delta info to be pushed out (accountId, attributes).
+     * @param subject user / role to be created.
+     * @return info to be pushed out (accountId, attributes).
+     * @throws JobExecutionException in case of generic failure
+     */
+    <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> beforeDelete(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final Map.Entry<String, Set<Attribute>> delta,
+            final T subject) throws JobExecutionException;
+
+    /**
      * Action to be executed after each local user synchronization.
      *
      * @param handler synchronization handler being executed.

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncActions.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncActions.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncActions.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/SyncActions.java Wed Jun 11 08:16:40 2014
@@ -44,6 +44,76 @@ public interface SyncActions extends Abs
             final T subject) throws JobExecutionException;
 
     /**
+     * Action to be executed before creating (and linking to the resource) 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 beforeAssign(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final SyncDelta delta,
+            final T subject) throws JobExecutionException;
+
+    /**
+     * Action to be executed before unlinking resource from the synchronized user and de-provisioning.
+     *
+     * @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 beforeUnassign(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final SyncDelta delta,
+            final T subject) throws JobExecutionException;
+
+    /**
+     * Action to be executed before de-provisioning action only.
+     *
+     * @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 beforeDeprovision(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final SyncDelta delta,
+            final T subject) throws JobExecutionException;
+
+    /**
+     * Action to be executed before unlinking resource from the synchronized user.
+     *
+     * @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 beforeUnlink(
+            final AbstractSyncopeResultHandler<?, ?> handler,
+            final SyncDelta delta,
+            final T subject) throws JobExecutionException;
+
+    /**
+     * Action to be executed before linking resource to the synchronized user.
+     *
+     * @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 beforeLink(
+            final AbstractSyncopeResultHandler<?, ?> 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.

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/AbstractSyncopeResultHandler.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/AbstractSyncopeResultHandler.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/AbstractSyncopeResultHandler.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/AbstractSyncopeResultHandler.java Wed Jun 11 08:16:40 2014
@@ -25,10 +25,14 @@ import org.apache.syncope.core.connid.Co
 import org.apache.syncope.core.notification.NotificationManager;
 import org.apache.syncope.core.persistence.beans.AbstractSyncTask;
 import org.apache.syncope.core.propagation.Connector;
+import org.apache.syncope.core.rest.controller.RoleController;
+import org.apache.syncope.core.rest.controller.UserController;
 import org.apache.syncope.core.rest.data.RoleDataBinder;
 import org.apache.syncope.core.rest.data.UserDataBinder;
 import org.apache.syncope.core.sync.AbstractSyncActions;
 import org.apache.syncope.core.sync.SyncResult;
+import org.apache.syncope.core.workflow.role.RoleWorkflowAdapter;
+import org.apache.syncope.core.workflow.user.UserWorkflowAdapter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -40,6 +44,13 @@ public abstract class AbstractSyncopeRes
      */
     protected static final Logger LOG = LoggerFactory.getLogger(AbstractSyncopeResultHandler.class);
 
+    
+    @Autowired
+    protected UserController userController;
+
+    @Autowired
+    protected RoleController roleController;
+    
     /**
      * User data binder.
      */
@@ -71,6 +82,18 @@ public abstract class AbstractSyncopeRes
     protected AuditManager auditManager;
 
     /**
+     * User workflow adapter.
+     */
+    @Autowired
+    protected UserWorkflowAdapter uwfAdapter;
+
+    /**
+     * Role workflow adapter.
+     */
+    @Autowired
+    protected RoleWorkflowAdapter rwfAdapter;
+
+    /**
      * Syncing connector.
      */
     protected Connector connector;

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java Wed Jun 11 08:16:40 2014
@@ -35,6 +35,7 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
 import org.apache.syncope.core.propagation.TimeoutException;
 import org.apache.syncope.core.propagation.impl.AbstractPropagationTaskExecutor;
+import org.apache.syncope.core.rest.controller.AbstractAttributableController;
 import org.apache.syncope.core.sync.PushActions;
 import org.apache.syncope.core.sync.SyncResult;
 import org.apache.syncope.core.util.AttributableUtil;
@@ -86,6 +87,7 @@ public class SyncopePushResultHandler ex
         result.setId(attributable.getId());
         result.setSubjectType(attrUtil.getType());
 
+        final AbstractAttributableController<?, ?> controller;
         final AbstractAttributable toBeHandled;
         final Boolean enabled;
 
@@ -95,10 +97,12 @@ public class SyncopePushResultHandler ex
             enabled = getSyncTask().isSyncStatus()
                     ? ((SyncopeUser) toBeHandled).isSuspended() ? Boolean.FALSE : Boolean.TRUE
                     : null;
+            controller = userController;
         } else {
             toBeHandled = roleDataBinder.getRoleFromId(attributable.getId());
             result.setName(((SyncopeRole) toBeHandled).getName());
             enabled = null;
+            controller = roleController;
         }
 
         LOG.debug("Propagating {} with ID {} towards {}",
@@ -109,6 +113,8 @@ public class SyncopePushResultHandler ex
         ConnectorObject beforeObj = null;
         Map.Entry<String, Set<Attribute>> values = null;
 
+        String operation = null;
+
         try {
             values = MappingUtil.prepareAttributes(
                     attrUtil, // attributable util
@@ -129,26 +135,84 @@ public class SyncopePushResultHandler ex
             beforeObj = getRemoteObject(oclass, values.getKey(), getSyncTask().getResource().getName());
 
             if (beforeObj == null) {
-                result.setOperation(ResourceOperation.CREATE);
-                actions.beforeCreate(this, values, toBeHandled);
+                operation = getSyncTask().getUnmatchigRule().name().toLowerCase();
+                switch (getSyncTask().getUnmatchigRule()) {
+                    case ASSIGN:
+                        result.setOperation(ResourceOperation.CREATE);
+                        actions.beforeAssign(this, values, toBeHandled);
+                        controller.assign(
+                                toBeHandled.getId(),
+                                Collections.singleton(getSyncTask().getResource().getName()), true, null);
+                        break;
+                    case PROVISION:
+                        result.setOperation(ResourceOperation.CREATE);
+                        actions.beforeProvision(this, values, toBeHandled);
+                        controller.provision(
+                                toBeHandled.getId(),
+                                Collections.singleton(getSyncTask().getResource().getName()), true, null);
+                        break;
+                    case UNLINK:
+                        result.setOperation(ResourceOperation.NONE);
+                        actions.beforeUnlink(this, values, toBeHandled);
+                        controller.unlink(
+                                toBeHandled.getId(), Collections.singleton(getSyncTask().getResource().getName()));
+                        break;
+                    default:
+                    // do nothing
+                }
+
             } else {
-                result.setOperation(ResourceOperation.UPDATE);
-                actions.beforeUpdate(this, values, toBeHandled);
+                operation = getSyncTask().getMatchigRule().name().toLowerCase();
+                switch (getSyncTask().getMatchigRule()) {
+                    case UPDATE:
+                        result.setOperation(ResourceOperation.UPDATE);
+                        actions.beforeUpdate(this, values, toBeHandled);
+
+                        AbstractPropagationTaskExecutor.createOrUpdate(
+                                oclass,
+                                values.getKey(),
+                                values.getValue(),
+                                getSyncTask().getResource().getName(),
+                                getSyncTask().getResource().getPropagationMode(),
+                                beforeObj,
+                                connector,
+                                new HashSet<String>(),
+                                connObjectUtil);
+                        break;
+                    case DEPROVISION:
+                        result.setOperation(ResourceOperation.DELETE);
+                        actions.beforeDeprovision(this, values, toBeHandled);
+                        controller.deprovision(
+                                toBeHandled.getId(), Collections.singleton(getSyncTask().getResource().getName()));
+                        break;
+                    case UNASSIGN:
+                        result.setOperation(ResourceOperation.DELETE);
+                        actions.beforeUnassign(this, values, toBeHandled);
+                        controller.unlink(
+                                toBeHandled.getId(), Collections.singleton(getSyncTask().getResource().getName()));
+                        controller.deprovision(
+                                toBeHandled.getId(), Collections.singleton(getSyncTask().getResource().getName()));
+                        break;
+                    case LINK:
+                        result.setOperation(ResourceOperation.NONE);
+                        actions.beforeLink(this, values, toBeHandled);
+                        controller.link(
+                                toBeHandled.getId(), Collections.singleton(getSyncTask().getResource().getName()));
+                        break;
+                    case UNLINK:
+                        result.setOperation(ResourceOperation.NONE);
+                        actions.beforeUnlink(this, values, toBeHandled);
+                        controller.unlink(
+                                toBeHandled.getId(), Collections.singleton(getSyncTask().getResource().getName()));
+                        break;
+                    default:
+                    // do nothing
+                }
             }
 
-            AbstractPropagationTaskExecutor.createOrUpdate(
-                    oclass,
-                    values.getKey(),
-                    values.getValue(),
-                    getSyncTask().getResource().getName(),
-                    getSyncTask().getResource().getPropagationMode(),
-                    beforeObj,
-                    connector,
-                    new HashSet<String>(),
-                    connObjectUtil);
-
             result.setStatus(SyncResult.Status.SUCCESS);
             resultStatus = AuditElements.Result.SUCCESS;
+            output = getRemoteObject(oclass, values.getKey(), getSyncTask().getResource().getName());
         } catch (Exception e) {
             result.setStatus(SyncResult.Status.FAILURE);
             result.setMessage(e.getMessage());
@@ -158,24 +222,21 @@ public class SyncopePushResultHandler ex
             LOG.warn("Error pushing {} towards {}", toBeHandled, getSyncTask().getResource(), e);
             throw new JobExecutionException(e);
         } finally {
-
             actions.after(this, values, toBeHandled, result);
-
             notificationManager.createTasks(
                     AuditElements.EventCategoryType.PUSH,
                     AttributableType.USER.name().toLowerCase(),
                     syncTask.getResource().getName(),
-                    result.getOperation() == null ? null : result.getOperation().name().toLowerCase(),
+                    operation,
                     resultStatus,
                     beforeObj,
                     output,
                     toBeHandled);
-
             auditManager.audit(
                     AuditElements.EventCategoryType.PUSH,
                     AttributableType.USER.name().toLowerCase(),
                     syncTask.getResource().getName(),
-                    result.getOperation() == null ? null : result.getOperation().name().toLowerCase(),
+                    operation,
                     resultStatus,
                     beforeObj,
                     output,

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=1601824&r1=1601823&r2=1601824&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 Wed Jun 11 08:16:40 2014
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.sync.impl;
 
+import static org.apache.syncope.core.sync.impl.AbstractSyncopeResultHandler.LOG;
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -64,6 +65,7 @@ import org.apache.syncope.core.propagati
 import org.apache.syncope.core.propagation.PropagationException;
 import org.apache.syncope.core.propagation.PropagationTaskExecutor;
 import org.apache.syncope.core.propagation.impl.PropagationManager;
+import org.apache.syncope.core.rest.controller.AbstractAttributableController;
 import org.apache.syncope.core.rest.controller.UnauthorizedRoleException;
 import org.apache.syncope.core.rest.data.AttributableTransformer;
 import org.apache.syncope.core.sync.SyncActions;
@@ -72,8 +74,6 @@ import org.apache.syncope.core.sync.Sync
 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.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeUtil;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
@@ -127,18 +127,6 @@ public class SyncopeSyncResultHandler ex
     protected AttributableSearchDAO searchDAO;
 
     /**
-     * User workflow adapter.
-     */
-    @Autowired
-    protected UserWorkflowAdapter uwfAdapter;
-
-    /**
-     * Role workflow adapter.
-     */
-    @Autowired
-    protected RoleWorkflowAdapter rwfAdapter;
-
-    /**
      * Propagation Manager.
      */
     @Autowired
@@ -362,7 +350,7 @@ public class SyncopeSyncResultHandler ex
 
         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);
@@ -400,7 +388,34 @@ public class SyncopeSyncResultHandler ex
         return enabled;
     }
 
-    protected List<SyncResult> create(SyncDelta delta, final AttributableUtil attrUtil, final boolean dryRun)
+    protected List<SyncResult> assign(
+            final SyncDelta delta, final AttributableUtil attrUtil, final boolean dryRun)
+            throws JobExecutionException {
+
+        final AbstractAttributableTO subjectTO =
+                connObjectUtil.getAttributableTO(delta.getObject(), syncTask, attrUtil);
+
+        subjectTO.getResources().add(getSyncTask().getResource().getName());
+
+        return create(subjectTO, actions.beforeAssign(this, delta, subjectTO), attrUtil, "assign", dryRun);
+    }
+
+    protected List<SyncResult> create(
+            final SyncDelta delta, final AttributableUtil attrUtil, final boolean dryRun)
+            throws JobExecutionException {
+
+        final AbstractAttributableTO subjectTO =
+                connObjectUtil.getAttributableTO(delta.getObject(), syncTask, attrUtil);
+
+        return create(subjectTO, actions.beforeCreate(this, delta, subjectTO), attrUtil, "provision", dryRun);
+    }
+
+    private List<SyncResult> create(
+            final AbstractAttributableTO subjectTO,
+            SyncDelta delta,
+            final AttributableUtil attrUtil,
+            final String operation,
+            final boolean dryRun)
             throws JobExecutionException {
 
         if (!syncTask.isPerformCreate()) {
@@ -413,10 +428,6 @@ public class SyncopeSyncResultHandler ex
         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);
@@ -430,7 +441,7 @@ public class SyncopeSyncResultHandler ex
                 result.setName(((RoleTO) actual).getName());
             }
         } else {
-            Object output = null;
+            Object output;
             Result resultStatus;
 
             try {
@@ -489,9 +500,9 @@ public class SyncopeSyncResultHandler ex
                     AuditElements.EventCategoryType.SYNCHRONIZATION,
                     AttributableType.USER.name().toLowerCase(),
                     syncTask.getResource().getName(),
-                    "create",
+                    operation,
                     resultStatus,
-                    null, // searching for before object is too much expensive ... 
+                    null,
                     output,
                     delta);
 
@@ -499,9 +510,9 @@ public class SyncopeSyncResultHandler ex
                     AuditElements.EventCategoryType.SYNCHRONIZATION,
                     AttributableType.USER.name().toLowerCase(),
                     syncTask.getResource().getName(),
-                    "create",
+                    operation,
                     resultStatus,
-                    null, // searching for before object is too much expensive ... 
+                    null,
                     output,
                     delta);
         }
@@ -635,7 +646,7 @@ public class SyncopeSyncResultHandler ex
         for (Long id : subjects) {
             LOG.debug("About to update {}", id);
 
-            Object output = null;
+            Object output;
             AbstractAttributableTO before = null;
             Result resultStatus;
 
@@ -705,6 +716,207 @@ public class SyncopeSyncResultHandler ex
         return updResults;
     }
 
+    protected List<SyncResult> deprovision(
+            SyncDelta delta,
+            final List<Long> subjects,
+            final AttributableUtil attrUtil,
+            final boolean unlink,
+            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);
+
+        final List<SyncResult> updResults = new ArrayList<SyncResult>();
+
+        final AbstractAttributableController<?, ?> controller;
+        if (AttributableType.USER == attrUtil.getType()) {
+            controller = userController;
+        } else {
+            controller = roleController;
+        }
+
+        for (Long id : subjects) {
+            LOG.debug("About to unassign resource {}", id);
+
+            Object output;
+            Result resultStatus;
+
+            final SyncResult result = new SyncResult();
+            result.setOperation(ResourceOperation.DELETE);
+            result.setSubjectType(attrUtil.getType());
+            result.setStatus(SyncResult.Status.SUCCESS);
+            result.setId(id);
+
+            final AbstractAttributableTO before = controller.read(id);
+            result.setName(before instanceof UserTO ? UserTO.class.cast(before).getUsername()
+                    : before instanceof RoleTO ? RoleTO.class.cast(before).getName() : null);
+
+            try {
+                if (!dryRun) {
+                    if (unlink) {
+                        actions.beforeUnassign(this, delta, before);
+                        controller.unlink(id, Collections.<String>singleton(getSyncTask().getResource().getName()));
+                    } else {
+                        actions.beforeDeprovision(this, delta, before);
+                    }
+
+                    controller.deprovision(id, Collections.<String>singleton(getSyncTask().getResource().getName()));
+
+                    output = controller.read(id);
+                    actions.after(this, delta, AbstractAttributableTO.class.cast(output), result);
+                } else {
+                    output = before;
+                }
+
+                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(),
+                        unlink ? "unassign" : "deprovision",
+                        resultStatus,
+                        before,
+                        output,
+                        delta);
+
+                auditManager.audit(
+                        AuditElements.EventCategoryType.SYNCHRONIZATION,
+                        attrUtil.getType().name().toLowerCase(),
+                        syncTask.getResource().getName(),
+                        unlink ? "unassign" : "deprovision",
+                        resultStatus,
+                        before,
+                        output,
+                        delta);
+            }
+
+            LOG.debug("{} {} successfully updated", attrUtil.getType(), id);
+        }
+
+        return updResults;
+    }
+
+    protected List<SyncResult> link(
+            SyncDelta delta,
+            final List<Long> subjects,
+            final AttributableUtil attrUtil,
+            final boolean unlink,
+            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);
+
+        final List<SyncResult> updResults = new ArrayList<SyncResult>();
+
+        final AbstractAttributableController<?, ?> controller;
+        if (AttributableType.USER == attrUtil.getType()) {
+            controller = userController;
+        } else {
+            controller = roleController;
+        }
+
+        for (Long id : subjects) {
+            LOG.debug("About to unassign resource {}", id);
+
+            Object output;
+            Result resultStatus;
+
+            final SyncResult result = new SyncResult();
+            result.setOperation(ResourceOperation.NONE);
+            result.setSubjectType(attrUtil.getType());
+            result.setStatus(SyncResult.Status.SUCCESS);
+            result.setId(id);
+
+            final AbstractAttributableTO before = controller.read(id);
+            result.setName(before instanceof UserTO ? UserTO.class.cast(before).getUsername()
+                    : before instanceof RoleTO ? RoleTO.class.cast(before).getName() : null);
+
+            try {
+                if (!dryRun) {
+                    if (unlink) {
+                        actions.beforeUnlink(this, delta, before);
+                        controller.unlink(id, Collections.<String>singleton(getSyncTask().getResource().getName()));
+                    } else {
+                        actions.beforeLink(this, delta, before);
+                        controller.link(id, Collections.<String>singleton(getSyncTask().getResource().getName()));
+                    }
+
+                    output = controller.read(id);
+                    actions.after(this, delta, AbstractAttributableTO.class.cast(output), result);
+                } else {
+                    output = before;
+                }
+
+                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(),
+                        unlink ? "unlink" : "link",
+                        resultStatus,
+                        before,
+                        output,
+                        delta);
+
+                auditManager.audit(
+                        AuditElements.EventCategoryType.SYNCHRONIZATION,
+                        attrUtil.getType().name().toLowerCase(),
+                        syncTask.getResource().getName(),
+                        unlink ? "unlink" : "link",
+                        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 {
@@ -722,19 +934,22 @@ public class SyncopeSyncResultHandler ex
             Object output = null;
             Result resultStatus = Result.FAILURE;
 
+            AbstractAttributableTO before = null;
+
             try {
-                AbstractAttributableTO subjectTO = AttributableType.USER == attrUtil.getType()
+                before = AttributableType.USER == attrUtil.getType()
                         ? userDataBinder.getUserTO(id)
                         : roleDataBinder.getRoleTO(id);
-                delta = actions.beforeDelete(this, delta, subjectTO);
+
+                delta = actions.beforeDelete(this, delta, before);
 
                 final SyncResult result = new SyncResult();
                 result.setId(id);
-                if (subjectTO instanceof UserTO) {
-                    result.setName(((UserTO) subjectTO).getUsername());
+                if (before instanceof UserTO) {
+                    result.setName(((UserTO) before).getUsername());
                 }
-                if (subjectTO instanceof RoleTO) {
-                    result.setName(((RoleTO) subjectTO).getName());
+                if (before instanceof RoleTO) {
+                    result.setName(((RoleTO) before).getName());
                 }
                 result.setOperation(ResourceOperation.DELETE);
                 result.setSubjectType(attrUtil.getType());
@@ -771,7 +986,7 @@ public class SyncopeSyncResultHandler ex
                     }
                 }
 
-                actions.after(this, delta, subjectTO, result);
+                actions.after(this, delta, before, result);
                 delResults.add(result);
 
             } catch (NotFoundException e) {
@@ -787,7 +1002,7 @@ public class SyncopeSyncResultHandler ex
                         syncTask.getResource().getName(),
                         "delete",
                         resultStatus,
-                        null, // searching for before object is too much expensive ... 
+                        before,
                         output,
                         delta);
 
@@ -797,7 +1012,7 @@ public class SyncopeSyncResultHandler ex
                         syncTask.getResource().getName(),
                         "delete",
                         resultStatus,
-                        null, // searching for before object is too much expensive ... 
+                        before,
                         output,
                         delta);
             }
@@ -827,63 +1042,69 @@ public class SyncopeSyncResultHandler ex
         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 {
+        try {
+            List<Long> subjectIds = findExisting(uid, delta.getObject(), attrUtil);
+            if (subjectIds.size() > 1) {
                 switch (resAct) {
                     case IGNORE:
-                        LOG.error("More than one match {}", subjectIds);
-                        break;
+                        throw new IllegalStateException("More than one match " + subjectIds);
 
                     case FIRSTMATCH:
-                        results.addAll(update(delta, subjectIds.subList(0, 1), attrUtil, dryRun));
+                        subjectIds = subjectIds.subList(0, 1);
                         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));
+                        subjectIds = subjectIds.subList(subjectIds.size() - 1, subjectIds.size());
                         break;
 
                     default:
+                    // keep subjectIds as is
                 }
             }
-        } 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:
+            if (SyncDeltaType.CREATE_OR_UPDATE == delta.getDeltaType()) {
+                if (subjectIds.isEmpty()) {
+                    switch (getSyncTask().getUnmatchigRule()) {
+                        case ASSIGN:
+                            results.addAll(assign(delta, attrUtil, dryRun));
+                            break;
+                        case PROVISION:
+                            results.addAll(create(delta, attrUtil, dryRun));
+                            break;
+                        default:
+                        // do nothing
+                    }
+                } else {
+                    switch (getSyncTask().getMatchigRule()) {
+                        case UPDATE:
+                            results.addAll(update(delta, subjectIds, attrUtil, dryRun));
+                            break;
+                        case DEPROVISION:
+                            results.addAll(deprovision(delta, subjectIds, attrUtil, false, dryRun));
+                            break;
+                        case UNASSIGN:
+                            results.addAll(deprovision(delta, subjectIds, attrUtil, true, dryRun));
+                            break;
+                        case LINK:
+                            results.addAll(link(delta, subjectIds, attrUtil, false, dryRun));
+                            break;
+                        case UNLINK:
+                            results.addAll(link(delta, subjectIds, attrUtil, true, dryRun));
+                            break;
+                        default:
+                        // do nothing
+                    }
+                }
+            } else if (SyncDeltaType.DELETE == delta.getDeltaType()) {
+                if (subjectIds.isEmpty()) {
+                    LOG.debug("No match found for deletion");
+                } else {
+                    results.addAll(delete(delta, subjectIds, attrUtil, dryRun));
                 }
             }
+        } catch (IllegalStateException e) {
+            LOG.warn(e.getMessage());
         }
     }
 }

Modified: syncope/trunk/core/src/test/java/org/apache/syncope/core/persistence/relationships/TaskTest.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/test/java/org/apache/syncope/core/persistence/relationships/TaskTest.java?rev=1601824&r1=1601823&r2=1601824&view=diff
==============================================================================
--- syncope/trunk/core/src/test/java/org/apache/syncope/core/persistence/relationships/TaskTest.java (original)
+++ syncope/trunk/core/src/test/java/org/apache/syncope/core/persistence/relationships/TaskTest.java Wed Jun 11 08:16:40 2014
@@ -119,8 +119,7 @@ public class TaskTest extends AbstractDA
         task.addExec(execution);
         execution.setStartDate(new Date());
 
-        task = taskDAO.save(task);
-
+        taskDAO.save(task);
         taskDAO.flush();
 
         task = taskDAO.find(1L);
@@ -142,8 +141,7 @@ public class TaskTest extends AbstractDA
         task.addExec(execution);
         execution.setMessage("A message");
 
-        task = taskDAO.save(task);
-
+        taskDAO.save(task);
         taskDAO.flush();
 
         task = taskDAO.find(4L);
@@ -165,8 +163,7 @@ public class TaskTest extends AbstractDA
         task.addExec(execution);
         execution.setMessage("A message");
 
-        task = taskDAO.save(task);
-
+        taskDAO.save(task);
         taskDAO.flush();
 
         task = taskDAO.find(13L);

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=1601824&r1=1601823&r2=1601824&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 Wed Jun 11 08:16:40 2014
@@ -55,6 +55,8 @@ import org.apache.syncope.common.types.T
 import org.apache.syncope.common.types.TraceLevel;
 import org.apache.syncope.common.SyncopeClientException;
 import org.apache.syncope.common.to.PushTaskTO;
+import org.apache.syncope.common.types.MatchingRule;
+import org.apache.syncope.common.types.UnmatchingRule;
 import org.apache.syncope.common.wrap.PushActionClass;
 import org.apache.syncope.core.sync.TestSyncActions;
 import org.apache.syncope.core.sync.TestSyncRule;
@@ -148,6 +150,7 @@ public class TaskTestITCase extends Abst
                 SyncopeClient.getUserSearchConditionBuilder().hasNotResources(RESOURCE_NAME_TESTDB2).query());
         task.setRoleFilter(
                 SyncopeClient.getRoleSearchConditionBuilder().isNotNull("cool").query());
+        task.setMatchigRule(MatchingRule.LINK);
 
         final Response response = taskService.create(task);
         final PushTaskTO actual = getObject(response.getLocation(), TaskService.class, PushTaskTO.class);
@@ -159,6 +162,8 @@ public class TaskTestITCase extends Abst
         assertEquals(task.getJobClassName(), actual.getJobClassName());
         assertEquals(task.getUserFilter(), actual.getUserFilter());
         assertEquals(task.getRoleFilter(), actual.getRoleFilter());
+        assertEquals(UnmatchingRule.ASSIGN, actual.getUnmatchigRule());
+        assertEquals(MatchingRule.LINK, actual.getMatchigRule());
     }
 
     @Test
@@ -239,11 +244,15 @@ public class TaskTestITCase extends Abst
 
     @Test
     public void read() {
-        PropagationTaskTO taskTO = taskService.read(3L);
+        final PropagationTaskTO taskTO = taskService.read(3L);
 
         assertNotNull(taskTO);
         assertNotNull(taskTO.getExecutions());
         assertTrue(taskTO.getExecutions().isEmpty());
+        
+        final PushTaskTO pushTaskTO = taskService.<PushTaskTO>read(13L);
+        assertEquals(UnmatchingRule.ASSIGN, pushTaskTO.getUnmatchigRule());
+        assertEquals(MatchingRule.UPDATE, pushTaskTO.getMatchigRule());
     }
 
     @Test
@@ -969,9 +978,9 @@ public class TaskTestITCase extends Abst
         // Read sync task
         PushTaskTO task = taskService.<PushTaskTO>read(13L);
         assertNotNull(task);
-        
+
         assertEquals("Vivaldi", userService.read(3L).getAttrMap().get("surname").getValues().get(0));
-        
+
         task.setUserFilter(SyncopeClient.getUserSearchConditionBuilder().is("surname").equalTo("Vivaldi").query());
         taskService.update(13L, task);
         assertEquals(task.getUserFilter(), taskService.<PushTaskTO>read(13L).getUserFilter());
@@ -983,10 +992,10 @@ public class TaskTestITCase extends Abst
         assertEquals(0, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='bellini'").size());
         assertEquals(0, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='rossini'").size());
         assertEquals(0, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='puccini'").size());
-        
+
         assertEquals("vivaldi",
                 jdbcTemplate.queryForObject("SELECT ID FROM test2 WHERE ID=?", String.class, "vivaldi"));
-        
+
         jdbcTemplate.execute("DELETE FROM test2 WHERE ID='vivaldi'");
 
         task.setUserFilter(null);