Repository: syncope Updated Branches: refs/heads/master 89ef51691 -> 85807bc5f
[SYNCOPE-923] Fix provided Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/85807bc5 Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/85807bc5 Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/85807bc5 Branch: refs/heads/master Commit: 85807bc5f8fe07f0ead635c1e1afc2b11708ef15 Parents: 89ef516 Author: Francesco Chicchiriccò <[email protected]> Authored: Tue Aug 23 12:30:52 2016 +0200 Committer: Francesco Chicchiriccò <[email protected]> Committed: Tue Aug 23 12:30:52 2016 +0200 ---------------------------------------------------------------------- .../test/resources/domains/MasterContent.xml | 2 +- .../pushpull/AbstractPullResultHandler.java | 76 ++++++++++---------- fit/build-tools/src/main/resources/testdb.sql | 1 + .../apache/syncope/fit/core/PullTaskITCase.java | 17 ++++- .../resources/scriptedsql/CreateScript.groovy | 2 +- .../resources/scriptedsql/DeleteScript.groovy | 2 +- .../resources/scriptedsql/SearchScript.groovy | 2 +- .../resources/scriptedsql/SyncScript.groovy | 2 +- 8 files changed, 60 insertions(+), 44 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/85807bc5/core/persistence-jpa/src/test/resources/domains/MasterContent.xml ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml index 7976010..610c1cf 100644 --- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml +++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml @@ -1152,7 +1152,7 @@ under the License. objectClassName="__ACCOUNT__" resource_id="resource-testdb" anyTypeKind="USER" entityKey="1417acbe-cbf6-4277-9372-e75e04f97000" attributes='[{"name":"__PASSWORD__","value":[{"readOnly":false,"disposed":false,"encryptedBytes":"m9nh2US0Sa6m+cXccCq0Xw==","base64SHA1Hash":"GFJ69qfjxEOdrmt+9q+0Cw2uz60="}]},{"name":"__NAME__","value":["userId"],"nameValue":"userId"},{"name":"fullname","value":["fullname"]},{"name":"type","value":["type"]}]'/> <Task DTYPE="PullTask" id="30cfd653-257b-495f-8665-281281dbcb3d" name="Scripted SQL" resource_id="resource-db-scripted" - destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" performCreate="1" performUpdate="1" performDelete="1" syncStatus="0" pullMode="INCREMENTAL" + destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" performCreate="1" performUpdate="1" performDelete="0" syncStatus="0" pullMode="INCREMENTAL" unmatchingRule="PROVISION" matchingRule="UPDATE" active="1"/> <MailTemplate id="requestPasswordReset" http://git-wip-us.apache.org/repos/asf/syncope/blob/85807bc5/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java index 2528308..2883a6a 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java @@ -80,37 +80,8 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan protected abstract AnyTO doCreate(AnyTO anyTO, SyncDelta delta, ProvisioningReport result); - protected AnyTO doLink(final AnyTO before, final boolean unlink) { - AnyPatch patch = newPatch(before.getKey()); - patch.setKey(before.getKey()); - patch.getResources().add(new StringPatchItem.Builder(). - operation(unlink ? PatchOperation.DELETE : PatchOperation.ADD_REPLACE). - value(profile.getTask().getResource().getKey()).build()); - - return getAnyTO(update(patch).getResult()); - } - protected abstract AnyTO doUpdate(AnyTO before, AnyPatch anyPatch, SyncDelta delta, ProvisioningReport result); - protected AnyPatch doDeprovision(final AnyTypeKind kind, final String key, final boolean unlink) { - PropagationByResource propByRes = new PropagationByResource(); - propByRes.add(ResourceOperation.DELETE, profile.getTask().getResource().getKey()); - taskExecutor.execute(propagationManager.getDeleteTasks( - kind, - key, - propByRes, - null)); - - AnyPatch anyPatch = null; - if (unlink) { - anyPatch = newPatch(key); - anyPatch.getResources().add(new StringPatchItem.Builder(). - operation(PatchOperation.DELETE). - value(profile.getTask().getResource().getKey()).build()); - } - return anyPatch; - } - protected void doDelete(final AnyTypeKind kind, final String key) { PropagationByResource propByRes = new PropagationByResource(); propByRes.add(ResourceOperation.DELETE, profile.getTask().getResource().getKey()); @@ -189,6 +160,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan if (!profile.getTask().isPerformCreate()) { LOG.debug("PullTask not configured for create"); + finalize(UnmatchingRule.toEventName(UnmatchingRule.ASSIGN), Result.SUCCESS, null, null, delta); return Collections.<ProvisioningReport>emptyList(); } @@ -204,6 +176,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan if (profile.isDryRun()) { result.setKey(null); + finalize(UnmatchingRule.toEventName(UnmatchingRule.ASSIGN), Result.SUCCESS, null, null, delta); } else { SyncDelta actionedDelta = delta; for (PullActions action : profile.getActions()) { @@ -222,6 +195,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan if (!profile.getTask().isPerformCreate()) { LOG.debug("PullTask not configured for create"); + finalize(UnmatchingRule.toEventName(UnmatchingRule.PROVISION), Result.SUCCESS, null, null, delta); return Collections.<ProvisioningReport>emptyList(); } @@ -235,6 +209,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan if (profile.isDryRun()) { result.setKey(null); + finalize(UnmatchingRule.toEventName(UnmatchingRule.PROVISION), Result.SUCCESS, null, null, delta); } else { SyncDelta actionedDelta = delta; for (PullActions action : profile.getActions()) { @@ -310,6 +285,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan if (!profile.getTask().isPerformUpdate()) { LOG.debug("PullTask not configured for update"); + finalize(MatchingRule.toEventName(MatchingRule.UPDATE), Result.SUCCESS, null, null, delta); return Collections.<ProvisioningReport>emptyList(); } @@ -400,6 +376,9 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan if (!profile.getTask().isPerformUpdate()) { LOG.debug("PullTask not configured for update"); + finalize(unlink + ? MatchingRule.toEventName(MatchingRule.UNASSIGN) + : MatchingRule.toEventName(MatchingRule.DEPROVISION), Result.SUCCESS, null, null, delta); return Collections.<ProvisioningReport>emptyList(); } @@ -444,7 +423,21 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan } } - AnyPatch anyPatch = doDeprovision(provision.getAnyType().getKind(), key, unlink); + PropagationByResource propByRes = new PropagationByResource(); + propByRes.add(ResourceOperation.DELETE, profile.getTask().getResource().getKey()); + taskExecutor.execute(propagationManager.getDeleteTasks( + provision.getAnyType().getKind(), + key, + propByRes, + null)); + + AnyPatch anyPatch = null; + if (unlink) { + anyPatch = newPatch(key); + anyPatch.getResources().add(new StringPatchItem.Builder(). + operation(PatchOperation.DELETE). + value(profile.getTask().getResource().getKey()).build()); + } if (anyPatch == null) { output = getAnyTO(key); } else { @@ -495,6 +488,9 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan if (!profile.getTask().isPerformUpdate()) { LOG.debug("PullTask not configured for update"); + finalize(unlink + ? MatchingRule.toEventName(MatchingRule.UNLINK) + : MatchingRule.toEventName(MatchingRule.LINK), Result.SUCCESS, null, null, delta); return Collections.<ProvisioningReport>emptyList(); } @@ -539,7 +535,12 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan } } - output = doLink(before, unlink); + AnyPatch patch = newPatch(before.getKey()); + patch.getResources().add(new StringPatchItem.Builder(). + operation(unlink ? PatchOperation.DELETE : PatchOperation.ADD_REPLACE). + value(profile.getTask().getResource().getKey()).build()); + + output = getAnyTO(update(patch).getResult()); for (PullActions action : profile.getActions()) { action.after(profile, delta, AnyTO.class.cast(output), result); @@ -566,7 +567,8 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan resultStatus = Result.FAILURE; } } - finalize(unlink ? MatchingRule.toEventName(MatchingRule.UNLINK) + finalize(unlink + ? MatchingRule.toEventName(MatchingRule.UNLINK) : MatchingRule.toEventName(MatchingRule.LINK), resultStatus, before, output, delta); } updResults.add(result); @@ -583,6 +585,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan if (!profile.getTask().isPerformDelete()) { LOG.debug("PullTask not configured for delete"); + finalize(ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, delta); return Collections.<ProvisioningReport>emptyList(); } @@ -660,11 +663,9 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan result.setAnyType(provision.getAnyType().getKey()); result.setStatus(ProvisioningReport.Status.SUCCESS); - if (!profile.isDryRun()) { - finalize(matching - ? MatchingRule.toEventName(MatchingRule.IGNORE) - : UnmatchingRule.toEventName(UnmatchingRule.IGNORE), Result.SUCCESS, null, null, delta); - } + finalize(matching + ? MatchingRule.toEventName(MatchingRule.IGNORE) + : UnmatchingRule.toEventName(UnmatchingRule.IGNORE), Result.SUCCESS, null, null, delta); return result; } @@ -780,6 +781,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan } } else if (SyncDeltaType.DELETE == delta.getDeltaType()) { if (anyKeys.isEmpty()) { + finalize(ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, delta); LOG.debug("No match found for deletion"); } else { profile.getResults().addAll(delete(delta, anyKeys, provision)); http://git-wip-us.apache.org/repos/asf/syncope/blob/85807bc5/fit/build-tools/src/main/resources/testdb.sql ---------------------------------------------------------------------- diff --git a/fit/build-tools/src/main/resources/testdb.sql b/fit/build-tools/src/main/resources/testdb.sql index 610c8a3..36d228b 100644 --- a/fit/build-tools/src/main/resources/testdb.sql +++ b/fit/build-tools/src/main/resources/testdb.sql @@ -47,4 +47,5 @@ CREATE TABLE testPRINTER ( id CHAR(36) PRIMARY KEY, printername VARCHAR(80), location VARCHAR(80), +deleted BOOLEAN DEFAULT FALSE, lastModification TIMESTAMP); http://git-wip-us.apache.org/repos/asf/syncope/blob/85807bc5/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java index c88131f..d157d78 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java @@ -30,6 +30,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -469,6 +470,13 @@ public class PullTaskITCase extends AbstractTaskITCase { resourceService.update(resource); resourceService.removeSyncToken(resource.getKey(), provision.getAnyType()); + // insert a deleted record in the external resource (SYNCOPE-923), which will be returned + // as sync event prior to the CREATE_OR_UPDATE events generated by the actions below (before pull) + JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource); + jdbcTemplate.update( + "INSERT INTO TESTPRINTER (id, printername, location, deleted, lastmodification) VALUES (?,?,?,?,?)", + UUID.randomUUID().toString(), "Mysterious Printer", "Nowhere", true, new Date()); + // 1. create printer on external resource AnyObjectTO anyObjectTO = AnyObjectITCase.getSampleTO("pull"); String originalLocation = anyObjectTO.getPlainAttrMap().get("location").getValues().get(0); @@ -487,8 +495,8 @@ public class PullTaskITCase extends AbstractTaskITCase { startsWith(PrefixMappingItemTransformer.PREFIX)); // 3. unlink any existing printer and delete from Syncope (printer is now only on external resource) - PagedResult<AnyObjectTO> matchingPrinters = anyObjectService.search(new AnyQuery.Builder().realm( - SyncopeConstants.ROOT_REALM). + PagedResult<AnyObjectTO> matchingPrinters = anyObjectService.search( + new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM). fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER"). is("location").equalTo("pull*").query()).build()); assertTrue(matchingPrinters.getSize() > 0); @@ -501,6 +509,11 @@ public class PullTaskITCase extends AbstractTaskITCase { anyObjectService.delete(printer.getKey()); } + // ensure that the pull task does not have the DELETE capability (SYNCOPE-923) + PullTaskTO pullTask = taskService.read("30cfd653-257b-495f-8665-281281dbcb3d", false); + assertNotNull(pullTask); + assertFalse(pullTask.isPerformDelete()); + // 4. pull execProvisioningTask(taskService, "30cfd653-257b-495f-8665-281281dbcb3d", 50, false); http://git-wip-us.apache.org/repos/asf/syncope/blob/85807bc5/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy index a5e1a5e..779c285 100644 --- a/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy +++ b/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy @@ -37,7 +37,7 @@ def sql = new Sql(connection); switch ( objectClass ) { case "__PRINTER__": - sql.execute("INSERT INTO TESTPRINTER (id, printername, location, lastmodification) values (?,?,?,?)", + sql.execute("INSERT INTO TESTPRINTER (id, printername, location, lastmodification) VALUES (?,?,?,?)", [ id, attributes.get("PRINTERNAME").get(0), http://git-wip-us.apache.org/repos/asf/syncope/blob/85807bc5/fit/core-reference/src/test/resources/scriptedsql/DeleteScript.groovy ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/resources/scriptedsql/DeleteScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/DeleteScript.groovy index cdd7f5b..a0ec224 100644 --- a/fit/core-reference/src/test/resources/scriptedsql/DeleteScript.groovy +++ b/fit/core-reference/src/test/resources/scriptedsql/DeleteScript.groovy @@ -35,7 +35,7 @@ assert uid != null switch ( objectClass ) { case "__PRINTER__": - sql.execute("DELETE FROM TESTPRINTER where id= ?",[uid]) + sql.execute("UPDATE TESTPRINTER SET deleted = ?, lastmodification = ? WHERE id = ?", [true, new Date(), uid]) break default: http://git-wip-us.apache.org/repos/asf/syncope/blob/85807bc5/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy index bb02d80..bba9ec4 100644 --- a/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy +++ b/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy @@ -83,7 +83,7 @@ if (query != null) { switch ( objectClass ) { case "__PRINTER__": - sql.eachRow("SELECT * FROM TESTPRINTER " + where, + sql.eachRow("SELECT * FROM TESTPRINTER " + where + ((where?.trim ()) ? "AND" : "WHERE") + " deleted <> TRUE", {result.add([__UID__:it.id, __NAME__:it.id, ID:it.id, PRINTERNAME:it.printername, LOCATION:it.location])} ); break http://git-wip-us.apache.org/repos/asf/syncope/blob/85807bc5/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy index f7ff18f..712dda9 100644 --- a/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy +++ b/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy @@ -75,7 +75,7 @@ if (action.equalsIgnoreCase("GET_LATEST_SYNC_TOKEN")) { sql.eachRow("SELECT * FROM TESTPRINTER WHERE lastmodification > ${lastmodification}", { result.add([ - operation:"CREATE_OR_UPDATE", + operation:it.deleted ? "DELETE": "CREATE_OR_UPDATE", uid:it.id.toString(), token:it.lastmodification.getTime(), attributes:[
