You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/04/12 10:42:04 UTC
[1/6] syncope git commit: Reworking 'Set admin credentials'
Repository: syncope
Updated Branches:
refs/heads/2_0_X 0189a50fd -> 73fab3dee
refs/heads/master 321102374 -> e5860a76a
Reworking 'Set admin credentials'
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/b7aacd8d
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/b7aacd8d
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/b7aacd8d
Branch: refs/heads/2_0_X
Commit: b7aacd8d0538da9dde6c8dc940b423a1d52ac560
Parents: 0189a50
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Apr 12 11:49:28 2018 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Apr 12 11:49:28 2018 +0200
----------------------------------------------------------------------
.../setadmincredentials.adoc | 23 +++++++++++++-------
1 file changed, 15 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/b7aacd8d/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/setadmincredentials.adoc
----------------------------------------------------------------------
diff --git a/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/setadmincredentials.adoc b/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/setadmincredentials.adoc
index 4292a06..10e24f0 100644
--- a/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/setadmincredentials.adoc
+++ b/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/setadmincredentials.adoc
@@ -21,22 +21,28 @@
[WARNING]
The procedure below affects only the `Master` <<domains,domain>>; for other domains check <<domains-management,above>>.
-The default password for the `admin` user is `password`.
-
The credentials are defined in the `security.properties` file; text encoding must be set to UTF-8:
-* `adminUser` - administrator username
-* `adminPassword` - SHA1 hash evaluation of cleartext password (represented as a sequence of 40 hexadecimal digits)
-* `adminPasswordAlgorithm` - algorithm to be used for hash evaluation (default value: SHA1)
+* `adminUser` - administrator username (default `admin`)
+* `adminPassword` - administrator password (default `password`)'s hashed value
+* `adminPasswordAlgorithm` - algorithm to be used for hash evaluation (default `SHA1`, others as
+`SHA256`, `SHA512`, `SMD5`, `SSHA1`, `SSHA256`, `SSHA512` and `BCRYPT` are supported)
-For GNU / Linux and Mac OS X, the SHA1 password can be obtained via the `sha1sum` command-line tool of
-http://www.gnu.org/software/coreutils/[GNU Core Utilities^]:
+[TIP]
+====
+The hashed password value can be obtained, depending on the actual algorithm, via various tools.
+As an example, for `SHA1` and GNU / Linux and Mac OS X, the `sha1sum` command-line tool of
+http://www.gnu.org/software/coreutils/[GNU Core Utilities^] can be used as follows:
[source,bash]
....
echo -n "new_password" | sha1sum
....
-For MS Windows, some options are available:
+
+Please beware that any shell special character must be properly escaped for the command above to produce the expected
+hashed value.
+
+Again about `SHA1`, for MS Windows some options are available:
* http://support.microsoft.com/kb/841290[MS File Checksum Integrity Verifier^] +
install, save your password to a file (e.g. `password.txt` without EOL) and issue at command line: +
@@ -47,3 +53,4 @@ fciv.exe -sha1 password.txt
* http://gnuwin32.sourceforge.net/[GnuWin32^] port of GNU utilities for MS Windows
* http://www.cygwin.com/[Cygwin^] Unix-like environment and command-line interface for Microsoft Windows (featuring
http://www.gnu.org/software/coreutils/[GNU Core Utilities^])
+====
[2/6] syncope git commit: [SYNCOPE-1299] Core implementation
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index 91eda38..3595886 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -84,6 +84,7 @@ import org.apache.syncope.common.rest.api.service.ResourceService;
import org.apache.syncope.common.rest.api.service.GroupService;
import org.apache.syncope.common.rest.api.service.MailTemplateService;
import org.apache.syncope.common.rest.api.service.RealmService;
+import org.apache.syncope.common.rest.api.service.ReconciliationService;
import org.apache.syncope.common.rest.api.service.RelationshipTypeService;
import org.apache.syncope.common.rest.api.service.ReportTemplateService;
import org.apache.syncope.common.rest.api.service.ResourceHistoryService;
@@ -227,6 +228,8 @@ public abstract class AbstractITCase {
protected static TaskService taskService;
+ protected static ReconciliationService reconciliationService;
+
protected static WorkflowService workflowService;
protected static MailTemplateService mailTemplateService;
@@ -305,6 +308,7 @@ public abstract class AbstractITCase {
reportTemplateService = adminClient.getService(ReportTemplateService.class);
reportService = adminClient.getService(ReportService.class);
taskService = adminClient.getService(TaskService.class);
+ reconciliationService = adminClient.getService(ReconciliationService.class);
policyService = adminClient.getService(PolicyService.class);
workflowService = adminClient.getService(WorkflowService.class);
mailTemplateService = adminClient.getService(MailTemplateService.class);
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java
new file mode 100644
index 0000000..d6cd241
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java
@@ -0,0 +1,137 @@
+/*
+ * 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.fit.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Date;
+import javax.sql.DataSource;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ReconciliationRequest;
+import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ReconciliationAction;
+import org.apache.syncope.fit.AbstractITCase;
+import org.identityconnectors.framework.common.objects.OperationalAttributes;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = { "classpath:testJDBCEnv.xml" })
+public class ReconciliationITCase extends AbstractITCase {
+
+ @Autowired
+ private DataSource testDataSource;
+
+ @Test
+ public void push() {
+ // 1. create printer, with no resources
+ AnyObjectTO printer = AnyObjectITCase.getSampleTO("reconciliation");
+ printer.getResources().clear();
+ printer = createAnyObject(printer).getEntity();
+ assertNotNull(printer.getKey());
+
+ // 2. verify no printer with that name is on the external resource's db
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
+ assertEquals(0, jdbcTemplate.queryForList(
+ "SELECT id FROM testPRINTER WHERE printername=?", printer.getName()).size());
+
+ // 3. verify reconciliation status
+ ReconciliationStatus status =
+ reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
+ assertNotNull(status);
+ assertNotNull(status.getOnSyncope());
+ assertNull(status.getOnResource());
+
+ // 4. push
+ ReconciliationRequest request = new ReconciliationRequest();
+ request.setAction(ReconciliationAction.PUSH);
+ request.setAnyKey(printer.getKey());
+ request.setAnyTypeKind(AnyTypeKind.ANY_OBJECT);
+ request.setResourceKey("resource-db-scripted");
+ reconciliationService.reconcile(request);
+
+ // 5. verify that printer is now propagated
+ assertEquals(1, jdbcTemplate.queryForList(
+ "SELECT id FROM testPRINTER WHERE printername=?", printer.getName()).size());
+
+ // 6. verify resource was not assigned
+ printer = anyObjectService.read(printer.getKey());
+ assertTrue(printer.getResources().isEmpty());
+
+ // 7. verify reconciliation status
+ status = reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
+ assertNotNull(status);
+ assertNotNull(status.getOnSyncope());
+ assertNotNull(status.getOnResource());
+
+ // __ENABLE__ management depends on the actual connector...
+ AttrTO enable = status.getOnSyncope().getAttr(OperationalAttributes.ENABLE_NAME);
+ if (enable != null) {
+ status.getOnSyncope().getAttrs().remove(enable);
+ }
+ assertEquals(status.getOnSyncope(), status.getOnResource());
+ }
+
+ @Test
+ public void pull() {
+ // 1. create printer, with no resources
+ AnyObjectTO printer = AnyObjectITCase.getSampleTO("reconciliation");
+ printer.getResources().clear();
+ printer = createAnyObject(printer).getEntity();
+ assertNotNull(printer.getKey());
+ assertNotEquals("Nowhere", printer.getPlainAttr("location").getValues().get(0));
+
+ // 2. create table into the external resource's db, with same name
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
+ jdbcTemplate.update(
+ "INSERT INTO TESTPRINTER (id, printername, location, deleted, lastmodification) VALUES (?,?,?,?,?)",
+ printer.getKey(), printer.getName(), "Nowhere", false, new Date());
+
+ // 3. verify reconciliation status
+ ReconciliationStatus status =
+ reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
+ assertNotNull(status);
+ assertNotNull(status.getOnSyncope());
+ assertNotNull(status.getOnResource());
+ assertNotEquals(status.getOnSyncope().getAttr("LOCATION"), status.getOnResource().getAttr("LOCATION"));
+
+ // 4. pull
+ ReconciliationRequest request = new ReconciliationRequest();
+ request.setAction(ReconciliationAction.PULL);
+ request.setAnyKey(printer.getKey());
+ request.setAnyTypeKind(AnyTypeKind.ANY_OBJECT);
+ request.setResourceKey("resource-db-scripted");
+ reconciliationService.reconcile(request);
+
+ // 5. verify reconciliation result (and resource is still not assigned)
+ printer = anyObjectService.read(printer.getKey());
+ assertEquals("Nowhere", printer.getPlainAttr("location").getValues().get(0));
+ assertTrue(printer.getResources().isEmpty());
+ }
+}
[3/6] syncope git commit: [SYNCOPE-1299] Core implementation
Posted by il...@apache.org.
[SYNCOPE-1299] Core implementation
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/73fab3de
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/73fab3de
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/73fab3de
Branch: refs/heads/2_0_X
Commit: 73fab3dee3f95029bc210a16f3c0bd57814e0920
Parents: b7aacd8
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Apr 12 11:50:16 2018 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Apr 12 11:50:16 2018 +0200
----------------------------------------------------------------------
.../common/lib/to/ProvisioningTaskTO.java | 9 +-
.../apache/syncope/common/lib/to/RealmTO.java | 6 +-
.../common/lib/to/ReconciliationRequest.java | 90 +++++++
.../common/lib/to/ReconciliationStatus.java | 56 +++++
.../common/lib/types/ClientExceptionType.java | 1 +
.../common/lib/types/ReconciliationAction.java | 28 +++
.../rest/api/service/ReconciliationService.java | 72 ++++++
.../syncope/core/logic/ReconciliationLogic.java | 238 +++++++++++++++++++
.../core/persistence/api/entity/AnyUtils.java | 7 +-
.../persistence/jpa/dao/JPAAnyObjectDAO.java | 4 +-
.../persistence/jpa/entity/JPAAnyUtils.java | 26 +-
.../api/pushpull/SyncopeSinglePullExecutor.java | 36 +++
.../api/pushpull/SyncopeSinglePushExecutor.java | 34 +++
.../provisioning/java/MappingManagerImpl.java | 2 +-
.../pushpull/AbstractPullResultHandler.java | 6 +-
.../pushpull/AbstractPushResultHandler.java | 2 +-
.../java/pushpull/PullJobDelegate.java | 49 ++--
.../provisioning/java/pushpull/PullUtils.java | 27 +--
.../java/pushpull/PushJobDelegate.java | 86 ++-----
.../java/pushpull/SinglePullJobDelegate.java | 167 +++++++++++++
.../java/pushpull/SinglePushJobDelegate.java | 110 +++++++++
.../java/utils/ConnObjectUtils.java | 4 +-
.../rest/cxf/service/AbstractAnyService.java | 26 +-
.../rest/cxf/service/AbstractServiceImpl.java | 15 ++
.../rest/cxf/service/AnyObjectServiceImpl.java | 2 +-
.../core/rest/cxf/service/GroupServiceImpl.java | 2 +-
.../cxf/service/ReconciliationServiceImpl.java | 53 +++++
.../core/rest/cxf/service/UserServiceImpl.java | 2 +-
.../org/apache/syncope/fit/AbstractITCase.java | 4 +
.../syncope/fit/core/ReconciliationITCase.java | 137 +++++++++++
30 files changed, 1136 insertions(+), 165 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisioningTaskTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisioningTaskTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisioningTaskTO.java
index bd45068..f17122e 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisioningTaskTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisioningTaskTO.java
@@ -20,11 +20,10 @@ package org.apache.syncope.common.lib.to;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
-
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
@@ -53,7 +52,7 @@ public abstract class ProvisioningTaskTO extends SchedTaskTO {
private MatchingRule matchingRule;
- private final Set<String> actionsClassNames = new HashSet<>();
+ private final List<String> actionsClassNames = new ArrayList<>();
@JsonProperty(required = true)
@XmlElement(required = true)
@@ -100,7 +99,7 @@ public abstract class ProvisioningTaskTO extends SchedTaskTO {
@XmlElementWrapper(name = "actionsClassNames")
@XmlElement(name = "actionsClassName")
@JsonProperty("actionsClassNames")
- public Set<String> getActionsClassNames() {
+ public List<String> getActionsClassNames() {
return actionsClassNames;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/common/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
index 3902cd3..ec52760 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
@@ -19,8 +19,10 @@
package org.apache.syncope.common.lib.to;
import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.PathParam;
@@ -50,7 +52,7 @@ public class RealmTO extends AbstractBaseBean implements EntityTO, TemplatableTO
private String passwordPolicy;
- private final Set<String> actionsClassNames = new HashSet<>();
+ private final List<String> actionsClassNames = new ArrayList<>();
@XmlJavaTypeAdapter(XmlGenericMapAdapter.class)
private final Map<String, AnyTO> templates = new HashMap<>();
@@ -111,7 +113,7 @@ public class RealmTO extends AbstractBaseBean implements EntityTO, TemplatableTO
@XmlElementWrapper(name = "actionsClassNames")
@XmlElement(name = "actionsClassName")
@JsonProperty("actionsClassNames")
- public Set<String> getActionsClassNames() {
+ public List<String> getActionsClassNames() {
return actionsClassNames;
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationRequest.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationRequest.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationRequest.java
new file mode 100644
index 0000000..d6cae93
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationRequest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ReconciliationAction;
+
+public class ReconciliationRequest extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -2592156800185957182L;
+
+ private AnyTypeKind anyTypeKind;
+
+ private String anyKey;
+
+ private String resourceKey;
+
+ private ReconciliationAction action;
+
+ private final List<String> actionsClassNames = new ArrayList<>();
+
+ @JsonProperty(required = true)
+ @XmlElement(required = true)
+ public AnyTypeKind getAnyTypeKind() {
+ return anyTypeKind;
+ }
+
+ public void setAnyTypeKind(final AnyTypeKind anyTypeKind) {
+ this.anyTypeKind = anyTypeKind;
+ }
+
+ @JsonProperty(required = true)
+ @XmlElement(required = true)
+ public String getAnyKey() {
+ return anyKey;
+ }
+
+ public void setAnyKey(final String anyKey) {
+ this.anyKey = anyKey;
+ }
+
+ @JsonProperty(required = true)
+ @XmlElement(required = true)
+ public String getResourceKey() {
+ return resourceKey;
+ }
+
+ public void setResourceKey(final String resourceKey) {
+ this.resourceKey = resourceKey;
+ }
+
+ @JsonProperty(required = true)
+ @XmlElement(required = true)
+ public ReconciliationAction getAction() {
+ return action;
+ }
+
+ public void setAction(final ReconciliationAction action) {
+ this.action = action;
+ }
+
+ @XmlElementWrapper(name = "actionsClassNames")
+ @XmlElement(name = "actionsClassName")
+ @JsonProperty("actionsClassNames")
+ public List<String> getActionsClassNames() {
+ return actionsClassNames;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationStatus.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationStatus.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationStatus.java
new file mode 100644
index 0000000..bd4f8b7
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationStatus.java
@@ -0,0 +1,56 @@
+/*
+ * 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.lib.to;
+
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Reconciliation status.
+ */
+@XmlRootElement(name = "reconciliationStatus")
+@XmlType
+public class ReconciliationStatus extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -8516345256596521490L;
+
+ private ConnObjectTO onSyncope;
+
+ private ConnObjectTO onResource;
+
+ @ApiModelProperty(readOnly = true)
+ public ConnObjectTO getOnSyncope() {
+ return onSyncope;
+ }
+
+ public void setOnSyncope(final ConnObjectTO onSyncope) {
+ this.onSyncope = onSyncope;
+ }
+
+ @ApiModelProperty(readOnly = true)
+ public ConnObjectTO getOnResource() {
+ return onResource;
+ }
+
+ public void setOnResource(final ConnObjectTO onResource) {
+ this.onResource = onResource;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
index c4077e5..f641a70 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
@@ -72,6 +72,7 @@ public enum ClientExceptionType {
InUseByNotifications(Response.Status.BAD_REQUEST),
Scheduling(Response.Status.BAD_REQUEST),
DelegatedAdministration(Response.Status.FORBIDDEN),
+ Reconciliation(Response.Status.BAD_REQUEST),
Unknown(Response.Status.BAD_REQUEST),
Workflow(Response.Status.BAD_REQUEST);
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReconciliationAction.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReconciliationAction.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReconciliationAction.java
new file mode 100644
index 0000000..19b68c2
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReconciliationAction.java
@@ -0,0 +1,28 @@
+/*
+ * 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.lib.types;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+@XmlEnum
+public enum ReconciliationAction {
+ PUSH,
+ PULL
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java
new file mode 100644
index 0000000..ddbbd5d
--- /dev/null
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java
@@ -0,0 +1,72 @@
+/*
+ * 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.rest.api.service;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.Authorization;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.ReconciliationRequest;
+import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+
+/**
+ * REST operations for tasks.
+ */
+@Api(tags = "Reconciliation", authorizations = {
+ @Authorization(value = "BasicAuthentication"),
+ @Authorization(value = "Bearer") })
+@Path("reconciliation")
+public interface ReconciliationService extends JAXRSService {
+
+ /**
+ * Gets current attributes on Syncope and on the given External Resource, related to given user, group or
+ * any object.
+ *
+ * @param anyTypeKind anyTypeKind
+ * @param anyKey user, group or any object: if value looks like a UUID then it is interpreted as key, otherwise as
+ * a (user)name
+ * @param resourceKey resource key
+ * @return reconciliation status
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ ReconciliationStatus status(
+ @NotNull @QueryParam("anyTypeKind") AnyTypeKind anyTypeKind,
+ @NotNull @QueryParam("anyKey") String anyKey,
+ @NotNull @QueryParam("resourceKey") String resourceKey);
+
+ /**
+ * Perform the required reconciliation action (PUSH or PULL) to the given user, group or any object and
+ * External Resource.
+ *
+ * @param request reconciliation request
+ */
+ @POST
+ @Consumes({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ void reconcile(@NotNull ReconciliationRequest request);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
new file mode 100644
index 0000000..7dee27b
--- /dev/null
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
@@ -0,0 +1,238 @@
+/*
+ * 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.logic;
+
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.collections4.IteratorUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.ReconciliationRequest;
+import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.ConnectorFactory;
+import org.apache.syncope.core.provisioning.api.MappingManager;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePullExecutor;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePushExecutor;
+import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.AttributeBuilder;
+import org.identityconnectors.framework.common.objects.AttributeUtil;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.Name;
+import org.identityconnectors.framework.common.objects.Uid;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ReconciliationLogic extends AbstractTransactionalLogic<AbstractBaseBean> {
+
+ @Autowired
+ private AnyUtilsFactory anyUtilsFactory;
+
+ @Autowired
+ private ExternalResourceDAO resourceDAO;
+
+ @Autowired
+ private VirSchemaDAO virSchemaDAO;
+
+ @Autowired
+ private RealmDAO realmDAO;
+
+ @Autowired
+ private MappingManager mappingManager;
+
+ @Autowired
+ private ConnectorFactory connFactory;
+
+ @Autowired
+ private SyncopeSinglePullExecutor singlePullExecutor;
+
+ @Autowired
+ private SyncopeSinglePushExecutor singlePushExecutor;
+
+ @SuppressWarnings("unchecked")
+ private Pair<Any<?>, Provision> init(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
+ AnyUtils anyUtils = anyUtilsFactory.getInstance(anyTypeKind);
+
+ Any<?> any = anyUtils.dao().authFind(anyKey);
+ if (any == null) {
+ throw new NotFoundException(anyTypeKind + " '" + anyKey + "'");
+ }
+
+ ExternalResource resource = resourceDAO.find(resourceKey);
+ if (resource == null) {
+ throw new NotFoundException("Resource '" + resourceKey + "'");
+ }
+ Provision provision = resource.getProvision(any.getType());
+ if (provision == null) {
+ throw new NotFoundException("Provision for " + any.getType() + " on Resource '" + resourceKey + "'");
+ }
+ if (provision.getMapping() == null) {
+ throw new NotFoundException("Mapping for " + any.getType() + " on Resource '" + resourceKey + "'");
+ }
+
+ return (Pair<Any<?>, Provision>) Pair.of(any, provision);
+ }
+
+ private ConnObjectTO getOnSyncope(final Any<?> any, final Provision provision, final String resourceKey) {
+ Pair<String, Set<Attribute>> attrs = mappingManager.prepareAttrs(any, null, false, true, provision);
+
+ MappingItem connObjectKey = provision.getMapping().getConnObjectKeyItem();
+ if (connObjectKey == null) {
+ throw new NotFoundException("No RemoteKey set for " + resourceKey);
+ }
+
+ ConnObjectTO connObjectTO = ConnObjectUtils.getConnObjectTO(attrs.getRight());
+ if (attrs.getLeft() != null) {
+ connObjectTO.getAttrs().add(new AttrTO.Builder().
+ schema(connObjectKey.getExtAttrName()).value(attrs.getLeft()).build());
+ connObjectTO.getAttrs().add(new AttrTO.Builder().
+ schema(Uid.NAME).value(attrs.getLeft()).build());
+ }
+
+ return connObjectTO;
+ }
+
+ private ConnObjectTO getOnResource(final Any<?> any, final Provision provision) {
+ // 1. build connObjectKeyItem
+ MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
+ if (connObjectKeyItem == null) {
+ throw new NotFoundException("ConnObjectKey for " + any.getType()
+ + " on resource '" + provision.getResource().getKey() + "'");
+ }
+ String connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, provision);
+
+ // 2. determine attributes to query
+ Set<MappingItem> linkinMappingItems = new HashSet<>();
+ for (VirSchema virSchema : virSchemaDAO.findByProvision(provision)) {
+ linkinMappingItems.add(virSchema.asLinkingMappingItem());
+ }
+ Iterator<MappingItem> mapItems = IteratorUtils.chainedIterator(
+ provision.getMapping().getItems().iterator(),
+ linkinMappingItems.iterator());
+
+ // 3. read from the underlying connector
+ ConnObjectTO connObjectTO = null;
+
+ Connector connector = connFactory.getConnector(provision.getResource());
+ ConnectorObject connectorObject = connector.getObject(
+ provision.getObjectClass(),
+ AttributeBuilder.build(connObjectKeyItem.getExtAttrName(), connObjectKeyValue),
+ MappingUtils.buildOperationOptions(mapItems));
+ if (connectorObject != null) {
+ Set<Attribute> attributes = connectorObject.getAttributes();
+ if (AttributeUtil.find(Uid.NAME, attributes) == null) {
+ attributes.add(connectorObject.getUid());
+ }
+ if (AttributeUtil.find(Name.NAME, attributes) == null) {
+ attributes.add(connectorObject.getName());
+ }
+
+ connObjectTO = ConnObjectUtils.getConnObjectTO(attributes);
+ }
+
+ return connObjectTO;
+ }
+
+ @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_GET_CONNOBJECT + "')")
+ public ReconciliationStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
+ Pair<Any<?>, Provision> init = init(anyTypeKind, anyKey, resourceKey);
+
+ ReconciliationStatus status = new ReconciliationStatus();
+ status.setOnSyncope(getOnSyncope(init.getLeft(), init.getRight(), resourceKey));
+ status.setOnResource(getOnResource(init.getLeft(), init.getRight()));
+
+ return status;
+ }
+
+ @PreAuthorize("hasRole('" + StandardEntitlement.TASK_EXECUTE + "')")
+ public void reconcile(final ReconciliationRequest request) {
+ Pair<Any<?>, Provision> init = init(request.getAnyTypeKind(), request.getAnyKey(), request.getResourceKey());
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
+ try {
+ List<ProvisioningReport> results = null;
+ switch (request.getAction()) {
+ case PUSH:
+ results = singlePushExecutor.push(
+ init.getRight(),
+ connFactory.getConnector(init.getRight().getResource()),
+ init.getLeft(),
+ request.getActionsClassNames());
+ break;
+
+ case PULL:
+ results = singlePullExecutor.pull(
+ init.getRight(),
+ connFactory.getConnector(init.getRight().getResource()),
+ init.getRight().getMapping().getConnObjectKeyItem().getExtAttrName(),
+ mappingManager.getConnObjectKeyValue(init.getLeft(), init.getRight()),
+ realmDAO.findByFullPath(init.getLeft().getRealm().getFullPath()),
+ request.getActionsClassNames());
+ break;
+
+ default:
+ }
+
+ if (results != null && !results.isEmpty()
+ && results.get(0).getStatus() == ProvisioningReport.Status.FAILURE) {
+
+ sce.getElements().add(results.get(0).getMessage());
+ }
+ } catch (JobExecutionException e) {
+ sce.getElements().add(e.getMessage());
+ }
+
+ if (!sce.isEmpty()) {
+ throw sce;
+ }
+ }
+
+ @Override
+ protected AbstractBaseBean resolveReference(final Method method, final Object... os)
+ throws UnresolvedReferenceException {
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
index 09079da..e59350e 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
@@ -22,11 +22,12 @@ import java.util.Set;
import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
+import org.apache.syncope.core.persistence.api.dao.AnyDAO;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
public interface AnyUtils {
- AnyTypeKind getAnyTypeKind();
+ AnyTypeKind anyTypeKind();
<T extends Any<?>> Class<T> anyClass();
@@ -45,9 +46,11 @@ public interface AnyUtils {
<T extends PlainAttrValue> T newPlainAttrUniqueValue();
<T extends PlainAttrValue> T clonePlainAttrValue(T src);
-
+
<T extends AnyTO> T newAnyTO();
+ <A extends Any<?>> AnyDAO<A> dao();
+
Set<ExternalResource> getAllResources(Any<?> any);
<S extends Schema> AllowedSchemas<S> getAllowedSchemas(Any<?> any, Class<S> reference);
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
index cab4a22..b95dae5 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
@@ -99,8 +99,8 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
@Transactional(readOnly = true)
@Override
- public String findKey(final String username) {
- return findKey(username, JPAAnyObject.TABLE);
+ public String findKey(final String name) {
+ return findKey(name, JPAAnyObject.TABLE);
}
@Transactional(readOnly = true)
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
index b687aa1..15fa17c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
@@ -32,6 +32,7 @@ import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
+import org.apache.syncope.core.persistence.api.dao.AnyDAO;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -113,7 +114,7 @@ public class JPAAnyUtils implements AnyUtils {
}
@Override
- public AnyTypeKind getAnyTypeKind() {
+ public AnyTypeKind anyTypeKind() {
return anyTypeKind;
}
@@ -337,6 +338,29 @@ public class JPAAnyUtils implements AnyUtils {
return result;
}
+ @Override
+ public <A extends Any<?>> AnyDAO<A> dao() {
+ AnyDAO<A> result = null;
+
+ switch (anyTypeKind) {
+ case USER:
+ result = (AnyDAO<A>) userDAO;
+ break;
+
+ case GROUP:
+ result = (AnyDAO<A>) groupDAO;
+ break;
+
+ case ANY_OBJECT:
+ result = (AnyDAO<A>) anyObjectDAO;
+ break;
+
+ default:
+ }
+
+ return result;
+ }
+
@Transactional(readOnly = true)
@Override
public Set<ExternalResource> getAllResources(final Any<?> any) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java
new file mode 100644
index 0000000..ba4d160
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java
@@ -0,0 +1,36 @@
+/*
+ * 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.provisioning.api.pushpull;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.quartz.JobExecutionException;
+
+public interface SyncopeSinglePullExecutor {
+
+ List<ProvisioningReport> pull(
+ Provision provision,
+ Connector connector,
+ String connObjectKey,
+ String connObjectValue,
+ Realm realm,
+ List<String> actionsClassNames) throws JobExecutionException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java
new file mode 100644
index 0000000..eb18f00
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.provisioning.api.pushpull;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.quartz.JobExecutionException;
+
+public interface SyncopeSinglePushExecutor {
+
+ List<ProvisioningReport> push(
+ Provision provision,
+ Connector connector,
+ Any<?> any,
+ List<String> actionsClassNames) throws JobExecutionException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index 33b9535..ac63ad7 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -648,7 +648,7 @@ public class MappingManagerImpl implements MappingManager {
IntAttrName intAttrName;
try {
- intAttrName = intAttrNameParser.parse(mapItem.getIntAttrName(), anyUtils.getAnyTypeKind());
+ intAttrName = intAttrNameParser.parse(mapItem.getIntAttrName(), anyUtils.anyTypeKind());
} catch (ParseException e) {
LOG.error("Invalid intAttrName '{}' specified, ignoring", mapItem.getIntAttrName(), e);
return;
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/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 25d63ee..da6f011 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
@@ -161,7 +161,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
ProvisioningReport ignoreResult = new ProvisioningReport();
ignoreResult.setOperation(ResourceOperation.NONE);
ignoreResult.setAnyType(provision == null
- ? getAnyUtils().getAnyTypeKind().name() : provision.getAnyType().getKey());
+ ? getAnyUtils().anyTypeKind().name() : provision.getAnyType().getKey());
ignoreResult.setStatus(ProvisioningReport.Status.IGNORE);
ignoreResult.setKey(null);
ignoreResult.setName(delta.getObject().getName().getNameValue());
@@ -863,7 +863,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
}
notificationManager.createTasks(AuditElements.EventCategoryType.PULL,
- getAnyUtils().getAnyTypeKind().name().toLowerCase(),
+ getAnyUtils().anyTypeKind().name().toLowerCase(),
profile.getTask().getResource().getKey(),
event,
result,
@@ -873,7 +873,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
furtherInput);
auditManager.audit(AuditElements.EventCategoryType.PULL,
- getAnyUtils().getAnyTypeKind().name().toLowerCase(),
+ getAnyUtils().anyTypeKind().name().toLowerCase(),
profile.getTask().getResource().getKey(),
event,
result,
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
index 7133e3a..fad3dfa 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
@@ -255,7 +255,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
: null;
LOG.debug("Propagating {} with key {} towards {}",
- anyUtils.getAnyTypeKind(), any.getKey(), profile.getTask().getResource());
+ anyUtils.anyTypeKind(), any.getKey(), profile.getTask().getResource());
Object output = null;
Result resultStatus = null;
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
index feffeba..9c9a040 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
@@ -80,14 +80,6 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
protected ProvisioningProfile<PullTask, PullActions> profile;
- protected RealmPullResultHandler rhandler;
-
- protected AnyObjectPullResultHandler ahandler;
-
- protected UserPullResultHandler uhandler;
-
- protected GroupPullResultHandler ghandler;
-
@Override
public void setLatestSyncToken(final ObjectClass objectClass, final SyncToken latestSyncToken) {
latestSyncTokens.put(objectClass, latestSyncToken);
@@ -168,30 +160,18 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
}
protected RealmPullResultHandler buildRealmHandler() {
- RealmPullResultHandler handler = (RealmPullResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (RealmPullResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultRealmPullResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
- handler.setPullExecutor(this);
-
- return handler;
}
protected AnyObjectPullResultHandler buildAnyObjectHandler() {
- AnyObjectPullResultHandler handler = (AnyObjectPullResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (AnyObjectPullResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultAnyObjectPullResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
- handler.setPullExecutor(this);
-
- return handler;
}
protected UserPullResultHandler buildUserHandler() {
- UserPullResultHandler handler = (UserPullResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (UserPullResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultUserPullResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
- handler.setPullExecutor(this);
-
- return handler;
}
protected GroupPullResultHandler buildGroupHandler() {
@@ -247,7 +227,9 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
OperationOptions options = MappingUtils.buildOperationOptions(
MappingUtils.getPullItems(orgUnit.getItems()).iterator());
- rhandler = buildRealmHandler();
+ RealmPullResultHandler handler = buildRealmHandler();
+ handler.setProfile(profile);
+ handler.setPullExecutor(this);
try {
switch (pullTask.getPullMode()) {
@@ -259,7 +241,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
connector.sync(
orgUnit.getObjectClass(),
orgUnit.getSyncToken(),
- rhandler,
+ handler,
options);
if (!dryRun) {
@@ -275,14 +257,14 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
connector.filteredReconciliation(orgUnit.getObjectClass(),
filterBuilder,
- rhandler,
+ handler,
options);
break;
case FULL_RECONCILIATION:
default:
connector.fullReconciliation(orgUnit.getObjectClass(),
- rhandler,
+ handler,
options);
break;
}
@@ -292,18 +274,15 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
}
// ...then provisions for any types
- ahandler = buildAnyObjectHandler();
- uhandler = buildUserHandler();
- ghandler = buildGroupHandler();
-
+ SyncopePullResultHandler handler;
+ GroupPullResultHandler ghandler = buildGroupHandler();
for (Provision provision : pullTask.getResource().getProvisions()) {
if (provision.getMapping() != null) {
status.set("Pulling " + provision.getObjectClass().getObjectClassValue());
- SyncopePullResultHandler handler;
switch (provision.getAnyType().getKind()) {
case USER:
- handler = uhandler;
+ handler = buildUserHandler();
break;
case GROUP:
@@ -312,8 +291,10 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
case ANY_OBJECT:
default:
- handler = ahandler;
+ handler = buildAnyObjectHandler();
}
+ handler.setProfile(profile);
+ handler.setPullExecutor(this);
try {
Set<MappingItem> linkinMappingItems = new HashSet<>();
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
index 46b6a22..28c31d1 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
@@ -28,11 +28,10 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.policy.PullPolicySpec;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
-import org.apache.syncope.core.persistence.api.dao.AnyDAO;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
@@ -154,10 +153,10 @@ public class PullUtils {
try {
List<String> anyKeys = match(connObj, provision, anyUtils);
if (anyKeys.isEmpty()) {
- LOG.debug("No matching {} found for {}, aborting", anyUtils.getAnyTypeKind(), connObj);
+ LOG.debug("No matching {} found for {}, aborting", anyUtils.anyTypeKind(), connObj);
} else {
if (anyKeys.size() > 1) {
- LOG.warn("More than one {} found {} - taking first only", anyUtils.getAnyTypeKind(), anyKeys);
+ LOG.warn("More than one {} found {} - taking first only", anyUtils.anyTypeKind(), anyKeys);
}
result = anyKeys.iterator().next();
@@ -170,14 +169,6 @@ public class PullUtils {
return result;
}
- private AnyDAO<?> getAnyDAO(final AnyTypeKind anyTypeKind) {
- return AnyTypeKind.USER == anyTypeKind
- ? userDAO
- : AnyTypeKind.ANY_OBJECT == anyTypeKind
- ? anyObjectDAO
- : groupDAO;
- }
-
private List<String> findByConnObjectKey(
final ConnectorObject connObj, final Provision provision, final AnyUtils anyUtils) {
@@ -217,7 +208,7 @@ public class PullUtils {
if (intAttrName.getField() != null) {
switch (intAttrName.getField()) {
case "key":
- Any<?> any = getAnyDAO(provision.getAnyType().getKind()).find(connObjectKey);
+ Any<?> any = anyUtils.dao().find(connObjectKey);
if (any != null) {
result.add(any.getKey());
}
@@ -260,17 +251,13 @@ public class PullUtils {
}
}
- List<? extends Any<?>> anys = getAnyDAO(provision.getAnyType().getKind()).
- findByPlainAttrValue(intAttrName.getSchemaName(), value);
- for (Any<?> any : anys) {
+ for (Any<?> any : anyUtils.dao().findByPlainAttrValue(intAttrName.getSchemaName(), value)) {
result.add(any.getKey());
}
break;
case DERIVED:
- anys = getAnyDAO(provision.getAnyType().getKind()).
- findByDerAttrValue(intAttrName.getSchemaName(), connObjectKey);
- for (Any<?> any : anys) {
+ for (Any<?> any : anyUtils.dao().findByDerAttrValue(intAttrName.getSchemaName(), connObjectKey)) {
result.add(any.getKey());
}
break;
@@ -331,7 +318,7 @@ public class PullUtils {
try {
return pullRule == null
? findByConnObjectKey(connObj, provision, anyUtils)
- : findByCorrelationRule(connObj, pullRule, anyUtils.getAnyTypeKind());
+ : findByCorrelationRule(connObj, pullRule, anyUtils.anyTypeKind());
} catch (RuntimeException e) {
LOG.error("Could not match {} with any existing {}", connObj, provision.getAnyType(), e);
return Collections.<String>emptyList();
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
index ae5e669..4f1e52f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
@@ -26,18 +26,15 @@ import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.search.SearchCondConverter;
import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.apache.syncope.core.persistence.api.dao.AnyDAO;
-import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
-import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.group.Group;
@@ -60,41 +57,21 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
/**
- * User DAO.
- */
- @Autowired
- protected UserDAO userDAO;
-
- /**
* Search DAO.
*/
@Autowired
protected AnySearchDAO searchDAO;
- /**
- * Group DAO.
- */
@Autowired
- protected GroupDAO groupDAO;
-
- @Autowired
- protected AnyObjectDAO anyObjectDAO;
+ protected RealmDAO realmDAO;
@Autowired
- protected RealmDAO realmDAO;
+ protected AnyUtilsFactory anyUtilsFactory;
protected ProvisioningProfile<PushTask, PushActions> profile;
protected final Map<String, MutablePair<Integer, String>> handled = new HashMap<>();
- protected RealmPushResultHandler rhandler;
-
- protected AnyObjectPushResultHandler ahandler;
-
- protected UserPushResultHandler uhandler;
-
- protected GroupPushResultHandler ghandler;
-
protected void reportHandled(final String anyType, final String key) {
MutablePair<Integer, String> pair = handled.get(anyType);
if (pair == null) {
@@ -122,25 +99,6 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
return status.get();
}
- protected AnyDAO<?> getAnyDAO(final AnyTypeKind anyTypeKind) {
- AnyDAO<?> result;
- switch (anyTypeKind) {
- case USER:
- result = userDAO;
- break;
-
- case GROUP:
- result = groupDAO;
- break;
-
- case ANY_OBJECT:
- default:
- result = anyObjectDAO;
- }
-
- return result;
- }
-
protected void doHandle(
final List<? extends Any<?>> anys,
final SyncopePushResultHandler handler,
@@ -165,35 +123,23 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
}
protected RealmPushResultHandler buildRealmHandler() {
- RealmPushResultHandler handler = (RealmPushResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (RealmPushResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultRealmPushResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
-
- return handler;
}
protected AnyObjectPushResultHandler buildAnyObjectHandler() {
- AnyObjectPushResultHandler handler = (AnyObjectPushResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (AnyObjectPushResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultAnyObjectPushResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
-
- return handler;
}
protected UserPushResultHandler buildUserHandler() {
- UserPushResultHandler handler = (UserPushResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (UserPushResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultUserPushResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
-
- return handler;
}
protected GroupPushResultHandler buildGroupHandler() {
- GroupPushResultHandler handler = (GroupPushResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (GroupPushResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultGroupPushResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
-
- return handler;
}
@Override
@@ -234,13 +180,14 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
if (pushTask.getResource().getOrgUnit() != null) {
status.set("Pushing realms");
- rhandler = buildRealmHandler();
+ RealmPushResultHandler handler = buildRealmHandler();
+ handler.setProfile(profile);
for (Realm realm : realmDAO.findDescendants(profile.getTask().getSourceRealm())) {
// Never push the root realm
if (realm.getParent() != null) {
try {
- rhandler.handle(realm.getKey());
+ handler.handle(realm.getKey());
reportHandled(SyncopeConstants.REALM_ANYTYPE, realm.getName());
} catch (Exception e) {
LOG.warn("Failure pushing '{}' on '{}'", realm, pushTask.getResource(), e);
@@ -251,30 +198,27 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
}
// ...then provisions for any types
- ahandler = buildAnyObjectHandler();
- uhandler = buildUserHandler();
- ghandler = buildGroupHandler();
-
for (Provision provision : pushTask.getResource().getProvisions()) {
if (provision.getMapping() != null) {
status.set("Pushing " + provision.getAnyType().getKey());
- AnyDAO<?> anyDAO = getAnyDAO(provision.getAnyType().getKind());
+ AnyDAO<?> anyDAO = anyUtilsFactory.getInstance(provision.getAnyType().getKind()).dao();
SyncopePushResultHandler handler;
switch (provision.getAnyType().getKind()) {
case USER:
- handler = uhandler;
+ handler = buildUserHandler();
break;
case GROUP:
- handler = ghandler;
+ handler = buildGroupHandler();
break;
case ANY_OBJECT:
default:
- handler = ahandler;
+ handler = buildAnyObjectHandler();
}
+ handler.setProfile(profile);
String filter = pushTask.getFilter(provision.getAnyType()) == null
? null
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
new file mode 100644
index 0000000..7df7f23
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
@@ -0,0 +1,167 @@
+/*
+ * 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.provisioning.java.pushpull;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.collections4.IteratorUtils;
+import org.apache.syncope.common.lib.types.ConflictResolutionAction;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.PullMode;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.task.PullTask;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.pushpull.GroupPullResultHandler;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
+import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullResultHandler;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePullExecutor;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+import org.identityconnectors.framework.common.objects.AttributeBuilder;
+import org.identityconnectors.framework.common.objects.OperationOptions;
+import org.identityconnectors.framework.common.objects.filter.Filter;
+import org.identityconnectors.framework.common.objects.filter.FilterBuilder;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSinglePullExecutor {
+
+ @Override
+ public List<ProvisioningReport> pull(
+ final Provision provision,
+ final Connector connector,
+ final String connObjectKey,
+ final String connObjectValue,
+ final Realm realm,
+ final List<String> actionsClassNames) throws JobExecutionException {
+
+ LOG.debug("Executing pull on {}", provision.getResource());
+
+ List<PullActions> actions = new ArrayList<>();
+ for (String className : actionsClassNames) {
+ try {
+ Class<?> actionsClass = Class.forName(className);
+ PullActions pullActions = (PullActions) ApplicationContextProvider.getBeanFactory().
+ createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
+
+ actions.add(pullActions);
+ } catch (Exception e) {
+ LOG.warn("Class '{}' not found", className, e);
+ }
+ }
+
+ try {
+ Set<MappingItem> linkinMappingItems = new HashSet<>();
+ for (VirSchema virSchema : virSchemaDAO.findByProvision(provision)) {
+ linkinMappingItems.add(virSchema.asLinkingMappingItem());
+ }
+ Iterator<MappingItem> mapItems = IteratorUtils.chainedIterator(
+ provision.getMapping().getItems().iterator(),
+ linkinMappingItems.iterator());
+ OperationOptions options = MappingUtils.buildOperationOptions(mapItems);
+
+ PullTask pullTask = entityFactory.newEntity(PullTask.class);
+ pullTask.setResource(provision.getResource());
+ pullTask.setMatchingRule(MatchingRule.UPDATE);
+ pullTask.setUnmatchingRule(UnmatchingRule.PROVISION);
+ pullTask.setPullMode(PullMode.FILTERED_RECONCILIATION);
+ pullTask.setPerformCreate(true);
+ pullTask.setPerformUpdate(true);
+ pullTask.setDestinationRealm(realm);
+
+ profile = new ProvisioningProfile<>(connector, pullTask);
+ profile.setDryRun(false);
+ profile.setResAct(ConflictResolutionAction.FIRSTMATCH);
+ profile.getActions().addAll(actions);
+
+ for (PullActions action : actions) {
+ action.beforeAll(profile);
+ }
+
+ SyncopePullResultHandler handler;
+ GroupPullResultHandler ghandler = buildGroupHandler();
+ switch (provision.getAnyType().getKind()) {
+ case USER:
+ handler = buildUserHandler();
+ break;
+
+ case GROUP:
+ handler = ghandler;
+ break;
+
+ case ANY_OBJECT:
+ default:
+ handler = buildAnyObjectHandler();
+ }
+ handler.setProfile(profile);
+ handler.setPullExecutor(this);
+
+ // execute filtered pull
+ connector.filteredReconciliation(
+ provision.getObjectClass(),
+ new AccountReconciliationFilterBuilder(connObjectKey, connObjectValue),
+ handler,
+ options);
+
+ try {
+ setGroupOwners(ghandler);
+ } catch (Exception e) {
+ LOG.error("While setting group owners", e);
+ }
+
+ for (PullActions action : actions) {
+ action.afterAll(profile);
+ }
+
+ return profile.getResults();
+ } catch (Exception e) {
+ throw e instanceof JobExecutionException
+ ? (JobExecutionException) e
+ : new JobExecutionException("While pulling from connector", e);
+ }
+ }
+
+ class AccountReconciliationFilterBuilder extends DefaultReconciliationFilterBuilder {
+
+ private final String key;
+
+ private final String value;
+
+ AccountReconciliationFilterBuilder(final String key, final String value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public Filter build() {
+ return FilterBuilder.equalTo(AttributeBuilder.build(key, value));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
new file mode 100644
index 0000000..eceb4fb
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
@@ -0,0 +1,110 @@
+/*
+ * 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.provisioning.java.pushpull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.task.PushTask;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
+import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopePushResultHandler;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePushExecutor;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSinglePushExecutor {
+
+ @Override
+ public List<ProvisioningReport> push(
+ final Provision provision,
+ final Connector connector,
+ final Any<?> any,
+ final List<String> actionsClassNames) throws JobExecutionException {
+
+ LOG.debug("Executing push on {}", provision.getResource());
+
+ List<PushActions> actions = new ArrayList<>();
+ for (String className : actionsClassNames) {
+ try {
+ Class<?> actionsClass = Class.forName(className);
+
+ PushActions pushActions = (PushActions) ApplicationContextProvider.getBeanFactory().
+ createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
+ actions.add(pushActions);
+ } catch (Exception e) {
+ LOG.info("Class '{}' not found", className, e);
+ }
+ }
+
+ try {
+ PushTask pushTask = entityFactory.newEntity(PushTask.class);
+ pushTask.setResource(provision.getResource());
+ pushTask.setMatchingRule(MatchingRule.UPDATE);
+ pushTask.setUnmatchingRule(UnmatchingRule.PROVISION);
+ pushTask.setPerformCreate(true);
+ pushTask.setPerformUpdate(true);
+
+ profile = new ProvisioningProfile<>(connector, pushTask);
+ profile.getActions().addAll(actions);
+ profile.setResAct(null);
+
+ for (PushActions action : actions) {
+ action.beforeAll(profile);
+ }
+
+ SyncopePushResultHandler handler;
+ switch (provision.getAnyType().getKind()) {
+ case USER:
+ handler = buildUserHandler();
+ break;
+
+ case GROUP:
+ handler = buildGroupHandler();
+ break;
+
+ case ANY_OBJECT:
+ default:
+ handler = buildAnyObjectHandler();
+ }
+ handler.setProfile(profile);
+
+ doHandle(Arrays.asList(any), handler, pushTask.getResource());
+
+ for (PushActions action : actions) {
+ action.afterAll(profile);
+ }
+
+ return profile.getResults();
+ } catch (Exception e) {
+ throw e instanceof JobExecutionException
+ ? (JobExecutionException) e
+ : new JobExecutionException("While pushing to connector", e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
index ad6db20..a17b168 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
@@ -246,8 +246,8 @@ public class ConnObjectUtils {
updated.setKey(key);
T anyPatch = null;
- if (null != anyUtils.getAnyTypeKind()) {
- switch (anyUtils.getAnyTypeKind()) {
+ if (null != anyUtils.anyTypeKind()) {
+ switch (anyUtils.anyTypeKind()) {
case USER:
UserTO originalUser = (UserTO) original;
UserTO updatedUser = (UserTO) updated;
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
index e7be4f7..5102b71 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
@@ -64,18 +64,6 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
protected abstract P newPatch(String key);
- protected String getActualKey(final String key) {
- String actualKey = key;
- if (!SyncopeConstants.UUID_PATTERN.matcher(key).matches()) {
- actualKey = getAnyDAO().findKey(key);
- if (actualKey == null) {
- throw new NotFoundException("User, Group or Any Object for " + key);
- }
- }
-
- return actualKey;
- }
-
@Override
public Set<AttrTO> read(final String key, final SchemaType schemaType) {
TO any = read(key);
@@ -124,7 +112,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
@Override
public TO read(final String key) {
- return getAnyLogic().read(getActualKey(key));
+ return getAnyLogic().read(getActualKey(getAnyDAO(), key));
}
@Override
@@ -161,7 +149,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
}
protected Response doUpdate(final P anyPatch) {
- anyPatch.setKey(getActualKey(anyPatch.getKey()));
+ anyPatch.setKey(getActualKey(getAnyDAO(), anyPatch.getKey()));
Date etagDate = findLastChange(anyPatch.getKey());
checkETag(String.valueOf(etagDate.getTime()));
@@ -196,21 +184,23 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
@Override
public Response update(final String key, final SchemaType schemaType, final AttrTO attrTO) {
- String actualKey = getActualKey(key);
+ String actualKey = getActualKey(getAnyDAO(), key);
addUpdateOrReplaceAttr(actualKey, schemaType, attrTO, PatchOperation.ADD_REPLACE);
return modificationResponse(read(actualKey, schemaType, attrTO.getSchema()));
}
@Override
public void delete(final String key, final SchemaType schemaType, final String schema) {
- String actualKey = getActualKey(key);
addUpdateOrReplaceAttr(
- actualKey, schemaType, new AttrTO.Builder().schema(schema).build(), PatchOperation.DELETE);
+ getActualKey(getAnyDAO(), key),
+ schemaType,
+ new AttrTO.Builder().schema(schema).build(),
+ PatchOperation.DELETE);
}
@Override
public Response delete(final String key) {
- String actualKey = getActualKey(key);
+ String actualKey = getActualKey(getAnyDAO(), key);
Date etagDate = findLastChange(actualKey);
checkETag(String.valueOf(etagDate.getTime()));
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractServiceImpl.java
index a040960..caef5d8 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractServiceImpl.java
@@ -37,12 +37,15 @@ import org.apache.cxf.jaxrs.ext.search.SearchCondition;
import org.apache.cxf.jaxrs.ext.search.SearchContext;
import org.apache.syncope.common.lib.AbstractBaseBean;
import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.PagedResult;
import org.apache.syncope.common.lib.to.ProvisioningResult;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.rest.api.service.JAXRSService;
import org.apache.syncope.common.rest.api.Preference;
import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.core.persistence.api.dao.AnyDAO;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.search.SearchCondVisitor;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
@@ -64,6 +67,18 @@ abstract class AbstractServiceImpl implements JAXRSService {
@Context
protected SearchContext searchContext;
+ protected String getActualKey(final AnyDAO<?> dao, final String pretendingKey) {
+ String actualKey = pretendingKey;
+ if (!SyncopeConstants.UUID_PATTERN.matcher(pretendingKey).matches()) {
+ actualKey = dao.findKey(pretendingKey);
+ if (actualKey == null) {
+ throw new NotFoundException("User, Group or Any Object for " + pretendingKey);
+ }
+ }
+
+ return actualKey;
+ }
+
protected boolean isNullPriorityAsync() {
return BooleanUtils.toBoolean(messageContext.getHttpHeaders().getHeaderString(RESTHeaders.NULL_PRIORITY_ASYNC));
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
index 961a328..3a7d40b 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
@@ -71,7 +71,7 @@ public class AnyObjectServiceImpl extends AbstractAnyService<AnyObjectTO, AnyObj
@Override
public Response update(final AnyObjectTO anyObjectTO) {
- anyObjectTO.setKey(getActualKey(anyObjectTO.getKey()));
+ anyObjectTO.setKey(getActualKey(getAnyDAO(), anyObjectTO.getKey()));
AnyObjectTO before = logic.read(anyObjectTO.getKey());
checkETag(before.getETagValue());
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
index 4e23d22..bc621e9 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
@@ -68,7 +68,7 @@ public class GroupServiceImpl extends AbstractAnyService<GroupTO, GroupPatch> im
@Override
public Response update(final GroupTO groupTO) {
- groupTO.setKey(getActualKey(groupTO.getKey()));
+ groupTO.setKey(getActualKey(getAnyDAO(), groupTO.getKey()));
GroupTO before = logic.read(groupTO.getKey());
checkETag(before.getETagValue());
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java
new file mode 100644
index 0000000..80d89d5
--- /dev/null
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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.cxf.service;
+
+import org.apache.syncope.common.lib.to.ReconciliationRequest;
+import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.rest.api.service.ReconciliationService;
+import org.apache.syncope.core.logic.ReconciliationLogic;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ReconciliationServiceImpl extends AbstractServiceImpl implements ReconciliationService {
+
+ @Autowired
+ private ReconciliationLogic logic;
+
+ @Autowired
+ private AnyUtilsFactory anyUtilsFactory;
+
+ @Override
+ public ReconciliationStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
+ return logic.status(
+ anyTypeKind,
+ getActualKey(anyUtilsFactory.getInstance(anyTypeKind).dao(), anyKey),
+ resourceKey);
+ }
+
+ @Override
+ public void reconcile(final ReconciliationRequest request) {
+ request.setAnyKey(
+ getActualKey(anyUtilsFactory.getInstance(request.getAnyTypeKind()).dao(), request.getAnyKey()));
+ logic.reconcile(request);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/73fab3de/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
index 4af144b..99dc24d 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
@@ -67,7 +67,7 @@ public class UserServiceImpl extends AbstractAnyService<UserTO, UserPatch> imple
@Override
public Response update(final UserTO userTO) {
- userTO.setKey(getActualKey(userTO.getKey()));
+ userTO.setKey(getActualKey(getAnyDAO(), userTO.getKey()));
UserTO before = logic.read(userTO.getKey());
checkETag(before.getETagValue());
[6/6] syncope git commit: [SYNCOPE-1299] Core implementation
Posted by il...@apache.org.
[SYNCOPE-1299] Core implementation
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/e5860a76
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/e5860a76
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/e5860a76
Branch: refs/heads/master
Commit: e5860a76a5584edf780df180eb9229ddf44de684
Parents: 3c4a351
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Apr 12 11:50:16 2018 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Apr 12 12:41:49 2018 +0200
----------------------------------------------------------------------
.../common/lib/to/ProvisioningTaskTO.java | 3 +-
.../common/lib/to/ReconciliationRequest.java | 100 ++++++++
.../common/lib/to/ReconciliationStatus.java | 56 +++++
.../common/lib/types/ClientExceptionType.java | 1 +
.../common/lib/types/ReconciliationAction.java | 28 +++
.../rest/api/service/ReconciliationService.java | 78 +++++++
.../syncope/core/logic/ReconciliationLogic.java | 232 +++++++++++++++++++
.../core/persistence/api/entity/AnyUtils.java | 7 +-
.../persistence/jpa/dao/JPAAnyObjectDAO.java | 4 +-
.../persistence/jpa/entity/JPAAnyUtils.java | 26 ++-
.../api/pushpull/SyncopeSinglePullExecutor.java | 37 +++
.../api/pushpull/SyncopeSinglePushExecutor.java | 34 +++
.../provisioning/java/MappingManagerImpl.java | 2 +-
.../pushpull/AbstractPullResultHandler.java | 6 +-
.../pushpull/AbstractPushResultHandler.java | 2 +-
.../java/pushpull/PullJobDelegate.java | 49 ++--
.../provisioning/java/pushpull/PullUtils.java | 23 +-
.../java/pushpull/PushJobDelegate.java | 86 ++-----
.../java/pushpull/SinglePullJobDelegate.java | 174 ++++++++++++++
.../java/pushpull/SinglePushJobDelegate.java | 117 ++++++++++
.../java/utils/ConnObjectUtils.java | 4 +-
.../rest/cxf/service/AbstractAnyService.java | 26 +--
.../rest/cxf/service/AbstractServiceImpl.java | 15 ++
.../rest/cxf/service/AnyObjectServiceImpl.java | 2 +-
.../core/rest/cxf/service/GroupServiceImpl.java | 2 +-
.../cxf/service/ReconciliationServiceImpl.java | 53 +++++
.../core/rest/cxf/service/UserServiceImpl.java | 2 +-
.../org/apache/syncope/fit/AbstractITCase.java | 4 +
.../syncope/fit/core/ReconciliationITCase.java | 134 +++++++++++
29 files changed, 1151 insertions(+), 156 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisioningTaskTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisioningTaskTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisioningTaskTO.java
index 27d4f9b..cdef683 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisioningTaskTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ProvisioningTaskTO.java
@@ -33,8 +33,7 @@ import org.apache.syncope.common.lib.types.UnmatchingRule;
@XmlRootElement(name = "provisioningTask")
@XmlType
@XmlSeeAlso({ PushTaskTO.class, PullTaskTO.class })
-@Schema(
- allOf = { SchedTaskTO.class },
+@Schema(allOf = { SchedTaskTO.class },
subTypes = { PushTaskTO.class, PullTaskTO.class }, discriminatorProperty = "@class")
public abstract class ProvisioningTaskTO extends SchedTaskTO {
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationRequest.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationRequest.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationRequest.java
new file mode 100644
index 0000000..2ebf699
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationRequest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ReconciliationAction;
+
+public class ReconciliationRequest extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -2592156800185957182L;
+
+ private AnyTypeKind anyTypeKind;
+
+ private String anyKey;
+
+ private String resourceKey;
+
+ private ReconciliationAction action;
+
+ private boolean remediation;
+
+ private final List<String> actions = new ArrayList<>();
+
+ @JsonProperty(required = true)
+ @XmlElement(required = true)
+ public AnyTypeKind getAnyTypeKind() {
+ return anyTypeKind;
+ }
+
+ public void setAnyTypeKind(final AnyTypeKind anyTypeKind) {
+ this.anyTypeKind = anyTypeKind;
+ }
+
+ @JsonProperty(required = true)
+ @XmlElement(required = true)
+ public String getAnyKey() {
+ return anyKey;
+ }
+
+ public void setAnyKey(final String anyKey) {
+ this.anyKey = anyKey;
+ }
+
+ @JsonProperty(required = true)
+ @XmlElement(required = true)
+ public String getResourceKey() {
+ return resourceKey;
+ }
+
+ public void setResourceKey(final String resourceKey) {
+ this.resourceKey = resourceKey;
+ }
+
+ @JsonProperty(required = true)
+ @XmlElement(required = true)
+ public ReconciliationAction getAction() {
+ return action;
+ }
+
+ public void setAction(final ReconciliationAction action) {
+ this.action = action;
+ }
+
+ public boolean isRemediation() {
+ return remediation;
+ }
+
+ public void setRemediation(final boolean remediation) {
+ this.remediation = remediation;
+ }
+
+ @XmlElementWrapper(name = "actions")
+ @XmlElement(name = "action")
+ @JsonProperty("actions")
+ public List<String> getActions() {
+ return actions;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationStatus.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationStatus.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationStatus.java
new file mode 100644
index 0000000..2d7af98
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReconciliationStatus.java
@@ -0,0 +1,56 @@
+/*
+ * 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.lib.to;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Reconciliation status.
+ */
+@XmlRootElement(name = "reconciliationStatus")
+@XmlType
+public class ReconciliationStatus extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -8516345256596521490L;
+
+ private ConnObjectTO onSyncope;
+
+ private ConnObjectTO onResource;
+
+ @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+ public ConnObjectTO getOnSyncope() {
+ return onSyncope;
+ }
+
+ public void setOnSyncope(final ConnObjectTO onSyncope) {
+ this.onSyncope = onSyncope;
+ }
+
+ @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+ public ConnObjectTO getOnResource() {
+ return onResource;
+ }
+
+ public void setOnResource(final ConnObjectTO onResource) {
+ this.onResource = onResource;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
index ada4a1e..8a8f744 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
@@ -74,6 +74,7 @@ public enum ClientExceptionType {
InUse(Response.Status.BAD_REQUEST),
Scheduling(Response.Status.BAD_REQUEST),
DelegatedAdministration(Response.Status.FORBIDDEN),
+ Reconciliation(Response.Status.BAD_REQUEST),
Unknown(Response.Status.BAD_REQUEST),
Workflow(Response.Status.BAD_REQUEST);
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReconciliationAction.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReconciliationAction.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReconciliationAction.java
new file mode 100644
index 0000000..19b68c2
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReconciliationAction.java
@@ -0,0 +1,28 @@
+/*
+ * 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.lib.types;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+@XmlEnum
+public enum ReconciliationAction {
+ PUSH,
+ PULL
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java
new file mode 100644
index 0000000..77eb840
--- /dev/null
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java
@@ -0,0 +1,78 @@
+/*
+ * 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.rest.api.service;
+
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.security.SecurityRequirements;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.ReconciliationRequest;
+import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+
+/**
+ * REST operations for tasks.
+ */
+@Tag(name = "Reconciliation")
+@SecurityRequirements({
+ @SecurityRequirement(name = "BasicAuthentication"),
+ @SecurityRequirement(name = "Bearer") })
+@Path("reconciliation")
+public interface ReconciliationService extends JAXRSService {
+
+ /**
+ * Gets current attributes on Syncope and on the given External Resource, related to given user, group or
+ * any object.
+ *
+ * @param anyTypeKind anyTypeKind
+ * @param anyKey user, group or any object: if value looks like a UUID then it is interpreted as key, otherwise as
+ * a (user)name
+ * @param resourceKey resource key
+ * @return reconciliation status
+ */
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ ReconciliationStatus status(
+ @NotNull @QueryParam("anyTypeKind") AnyTypeKind anyTypeKind,
+ @NotNull @QueryParam("anyKey") String anyKey,
+ @NotNull @QueryParam("resourceKey") String resourceKey);
+
+ /**
+ * Perform the required reconciliation action (PUSH or PULL) to the given user, group or any object and
+ * External Resource.
+ *
+ * @param request reconciliation request
+ */
+ @ApiResponses(
+ @ApiResponse(responseCode = "204", description = "Operation was successful"))
+ @POST
+ @Consumes({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
+ void reconcile(@NotNull ReconciliationRequest request);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
new file mode 100644
index 0000000..a36c159
--- /dev/null
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
@@ -0,0 +1,232 @@
+/*
+ * 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.logic;
+
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.collections.IteratorChain;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.ReconciliationRequest;
+import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.ConnectorFactory;
+import org.apache.syncope.core.provisioning.api.MappingManager;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePullExecutor;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePushExecutor;
+import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.AttributeBuilder;
+import org.identityconnectors.framework.common.objects.AttributeUtil;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.Name;
+import org.identityconnectors.framework.common.objects.Uid;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ReconciliationLogic extends AbstractTransactionalLogic<AbstractBaseBean> {
+
+ @Autowired
+ private AnyUtilsFactory anyUtilsFactory;
+
+ @Autowired
+ private ExternalResourceDAO resourceDAO;
+
+ @Autowired
+ private VirSchemaDAO virSchemaDAO;
+
+ @Autowired
+ private RealmDAO realmDAO;
+
+ @Autowired
+ private MappingManager mappingManager;
+
+ @Autowired
+ private ConnectorFactory connFactory;
+
+ @Autowired
+ private SyncopeSinglePullExecutor singlePullExecutor;
+
+ @Autowired
+ private SyncopeSinglePushExecutor singlePushExecutor;
+
+ @SuppressWarnings("unchecked")
+ private Pair<Any<?>, Provision> init(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
+ AnyUtils anyUtils = anyUtilsFactory.getInstance(anyTypeKind);
+
+ Any<?> any = anyUtils.dao().authFind(anyKey);
+ if (any == null) {
+ throw new NotFoundException(anyTypeKind + " '" + anyKey + "'");
+ }
+
+ ExternalResource resource = resourceDAO.find(resourceKey);
+ if (resource == null) {
+ throw new NotFoundException("Resource '" + resourceKey + "'");
+ }
+ Provision provision = resource.getProvision(any.getType()).orElseThrow(()
+ -> new NotFoundException("Provision for " + any.getType() + " on Resource '" + resourceKey + "'"));
+ if (provision.getMapping() == null) {
+ throw new NotFoundException("Mapping for " + any.getType() + " on Resource '" + resourceKey + "'");
+ }
+
+ return (Pair<Any<?>, Provision>) Pair.of(any, provision);
+ }
+
+ private ConnObjectTO getOnSyncope(final Any<?> any, final Provision provision, final String resourceKey) {
+ Pair<String, Set<Attribute>> attrs = mappingManager.prepareAttrs(any, null, false, true, provision);
+
+ MappingItem connObjectKey = provision.getMapping().getConnObjectKeyItem().orElseThrow(()
+ -> new NotFoundException("No RemoteKey set for " + resourceKey));
+
+ ConnObjectTO connObjectTO = ConnObjectUtils.getConnObjectTO(attrs.getRight());
+ if (attrs.getLeft() != null) {
+ connObjectTO.getAttrs().add(new AttrTO.Builder().
+ schema(connObjectKey.getExtAttrName()).value(attrs.getLeft()).build());
+ connObjectTO.getAttrs().add(new AttrTO.Builder().
+ schema(Uid.NAME).value(attrs.getLeft()).build());
+ }
+
+ return connObjectTO;
+ }
+
+ private ConnObjectTO getOnResource(final Any<?> any, final Provision provision) {
+ // 1. build connObjectKeyItem
+ MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision).orElseThrow(()
+ -> new NotFoundException("ConnObjectKey for " + any.getType()
+ + " on resource '" + provision.getResource().getKey() + "'"));
+ String connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, provision).orElseThrow(()
+ -> new NotFoundException("Value for ConnObjectKey for " + any.getType()
+ + " on resource '" + provision.getResource().getKey() + "'"));
+
+ // 2. determine attributes to query
+ Set<MappingItem> linkinMappingItems = virSchemaDAO.findByProvision(provision).stream().
+ map(virSchema -> virSchema.asLinkingMappingItem()).collect(Collectors.toSet());
+ Iterator<MappingItem> mapItems = new IteratorChain<>(
+ provision.getMapping().getItems().iterator(),
+ linkinMappingItems.iterator());
+
+ // 3. read from the underlying connector
+ ConnObjectTO connObjectTO = null;
+
+ Connector connector = connFactory.getConnector(provision.getResource());
+ ConnectorObject connectorObject = connector.getObject(
+ provision.getObjectClass(),
+ AttributeBuilder.build(connObjectKeyItem.getExtAttrName(), connObjectKeyValue),
+ MappingUtils.buildOperationOptions(mapItems));
+ if (connectorObject != null) {
+ Set<Attribute> attributes = connectorObject.getAttributes();
+ if (AttributeUtil.find(Uid.NAME, attributes) == null) {
+ attributes.add(connectorObject.getUid());
+ }
+ if (AttributeUtil.find(Name.NAME, attributes) == null) {
+ attributes.add(connectorObject.getName());
+ }
+
+ connObjectTO = ConnObjectUtils.getConnObjectTO(attributes);
+ }
+
+ return connObjectTO;
+ }
+
+ @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_GET_CONNOBJECT + "')")
+ public ReconciliationStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
+ Pair<Any<?>, Provision> init = init(anyTypeKind, anyKey, resourceKey);
+
+ ReconciliationStatus status = new ReconciliationStatus();
+ status.setOnSyncope(getOnSyncope(init.getLeft(), init.getRight(), resourceKey));
+ status.setOnResource(getOnResource(init.getLeft(), init.getRight()));
+
+ return status;
+ }
+
+ @PreAuthorize("hasRole('" + StandardEntitlement.TASK_EXECUTE + "')")
+ public void reconcile(final ReconciliationRequest request) {
+ Pair<Any<?>, Provision> init = init(request.getAnyTypeKind(), request.getAnyKey(), request.getResourceKey());
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
+ try {
+ List<ProvisioningReport> results = null;
+ switch (request.getAction()) {
+ case PUSH:
+ results = singlePushExecutor.push(
+ init.getRight(),
+ connFactory.getConnector(init.getRight().getResource()),
+ init.getLeft(),
+ request.getActions());
+ break;
+
+ case PULL:
+ results = singlePullExecutor.pull(
+ init.getRight(),
+ connFactory.getConnector(init.getRight().getResource()),
+ init.getRight().getMapping().getConnObjectKeyItem().get().getExtAttrName(),
+ mappingManager.getConnObjectKeyValue(init.getLeft(), init.getRight()).get(),
+ realmDAO.findByFullPath(init.getLeft().getRealm().getFullPath()),
+ request.isRemediation(),
+ request.getActions());
+ break;
+
+ default:
+ }
+
+ if (results != null && !results.isEmpty()
+ && results.get(0).getStatus() == ProvisioningReport.Status.FAILURE) {
+
+ sce.getElements().add(results.get(0).getMessage());
+ }
+ } catch (JobExecutionException e) {
+ sce.getElements().add(e.getMessage());
+ }
+
+ if (!sce.isEmpty()) {
+ throw sce;
+ }
+ }
+
+ @Override
+ protected AbstractBaseBean resolveReference(final Method method, final Object... os)
+ throws UnresolvedReferenceException {
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
index 09079da..e59350e 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
@@ -22,11 +22,12 @@ import java.util.Set;
import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
+import org.apache.syncope.core.persistence.api.dao.AnyDAO;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
public interface AnyUtils {
- AnyTypeKind getAnyTypeKind();
+ AnyTypeKind anyTypeKind();
<T extends Any<?>> Class<T> anyClass();
@@ -45,9 +46,11 @@ public interface AnyUtils {
<T extends PlainAttrValue> T newPlainAttrUniqueValue();
<T extends PlainAttrValue> T clonePlainAttrValue(T src);
-
+
<T extends AnyTO> T newAnyTO();
+ <A extends Any<?>> AnyDAO<A> dao();
+
Set<ExternalResource> getAllResources(Any<?> any);
<S extends Schema> AllowedSchemas<S> getAllowedSchemas(Any<?> any, Class<S> reference);
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
index abba39c..64550a7 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
@@ -92,8 +92,8 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
@Transactional(readOnly = true)
@Override
- public String findKey(final String username) {
- return findKey(username, JPAAnyObject.TABLE);
+ public String findKey(final String name) {
+ return findKey(name, JPAAnyObject.TABLE);
}
@Transactional(readOnly = true)
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
index b687aa1..15fa17c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
@@ -32,6 +32,7 @@ import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
+import org.apache.syncope.core.persistence.api.dao.AnyDAO;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -113,7 +114,7 @@ public class JPAAnyUtils implements AnyUtils {
}
@Override
- public AnyTypeKind getAnyTypeKind() {
+ public AnyTypeKind anyTypeKind() {
return anyTypeKind;
}
@@ -337,6 +338,29 @@ public class JPAAnyUtils implements AnyUtils {
return result;
}
+ @Override
+ public <A extends Any<?>> AnyDAO<A> dao() {
+ AnyDAO<A> result = null;
+
+ switch (anyTypeKind) {
+ case USER:
+ result = (AnyDAO<A>) userDAO;
+ break;
+
+ case GROUP:
+ result = (AnyDAO<A>) groupDAO;
+ break;
+
+ case ANY_OBJECT:
+ result = (AnyDAO<A>) anyObjectDAO;
+ break;
+
+ default:
+ }
+
+ return result;
+ }
+
@Transactional(readOnly = true)
@Override
public Set<ExternalResource> getAllResources(final Any<?> any) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java
new file mode 100644
index 0000000..bbf8430
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java
@@ -0,0 +1,37 @@
+/*
+ * 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.provisioning.api.pushpull;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.quartz.JobExecutionException;
+
+public interface SyncopeSinglePullExecutor {
+
+ List<ProvisioningReport> pull(
+ Provision provision,
+ Connector connector,
+ String connObjectKey,
+ String connObjectValue,
+ Realm realm,
+ boolean remediation,
+ List<String> actions) throws JobExecutionException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java
new file mode 100644
index 0000000..9068301
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.provisioning.api.pushpull;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.quartz.JobExecutionException;
+
+public interface SyncopeSinglePushExecutor {
+
+ List<ProvisioningReport> push(
+ Provision provision,
+ Connector connector,
+ Any<?> any,
+ List<String> actions) throws JobExecutionException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index 70a8647..83d8e76 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -674,7 +674,7 @@ public class MappingManagerImpl implements MappingManager {
IntAttrName intAttrName;
try {
- intAttrName = intAttrNameParser.parse(mapItem.getIntAttrName(), anyUtils.getAnyTypeKind());
+ intAttrName = intAttrNameParser.parse(mapItem.getIntAttrName(), anyUtils.anyTypeKind());
} catch (ParseException e) {
LOG.error("Invalid intAttrName '{}' specified, ignoring", mapItem.getIntAttrName(), e);
return;
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/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 3abbd84..35e0356 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
@@ -171,7 +171,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
ProvisioningReport ignoreResult = new ProvisioningReport();
ignoreResult.setOperation(ResourceOperation.NONE);
ignoreResult.setAnyType(provision == null
- ? getAnyUtils().getAnyTypeKind().name() : provision.getAnyType().getKey());
+ ? getAnyUtils().anyTypeKind().name() : provision.getAnyType().getKey());
ignoreResult.setStatus(ProvisioningReport.Status.IGNORE);
ignoreResult.setKey(null);
ignoreResult.setName(delta.getObject().getName().getNameValue());
@@ -914,7 +914,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
}
notificationManager.createTasks(AuditElements.EventCategoryType.PULL,
- getAnyUtils().getAnyTypeKind().name().toLowerCase(),
+ getAnyUtils().anyTypeKind().name().toLowerCase(),
profile.getTask().getResource().getKey(),
event,
result,
@@ -924,7 +924,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
furtherInput);
auditManager.audit(AuditElements.EventCategoryType.PULL,
- getAnyUtils().getAnyTypeKind().name().toLowerCase(),
+ getAnyUtils().anyTypeKind().name().toLowerCase(),
profile.getTask().getResource().getKey(),
event,
result,
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
index 5f74388..63f397b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
@@ -256,7 +256,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
: null;
LOG.debug("Propagating {} with key {} towards {}",
- anyUtils.getAnyTypeKind(), any.getKey(), profile.getTask().getResource());
+ anyUtils.anyTypeKind(), any.getKey(), profile.getTask().getResource());
Object output = null;
Result resultStatus = null;
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
index 9edfd6b..f8b73a2 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
@@ -80,14 +80,6 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
protected ProvisioningProfile<PullTask, PullActions> profile;
- protected RealmPullResultHandler rhandler;
-
- protected AnyObjectPullResultHandler ahandler;
-
- protected UserPullResultHandler uhandler;
-
- protected GroupPullResultHandler ghandler;
-
@Override
public void setLatestSyncToken(final ObjectClass objectClass, final SyncToken latestSyncToken) {
latestSyncTokens.put(objectClass, latestSyncToken);
@@ -168,30 +160,18 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
}
protected RealmPullResultHandler buildRealmHandler() {
- RealmPullResultHandler handler = (RealmPullResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (RealmPullResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultRealmPullResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
- handler.setPullExecutor(this);
-
- return handler;
}
protected AnyObjectPullResultHandler buildAnyObjectHandler() {
- AnyObjectPullResultHandler handler = (AnyObjectPullResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (AnyObjectPullResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultAnyObjectPullResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
- handler.setPullExecutor(this);
-
- return handler;
}
protected UserPullResultHandler buildUserHandler() {
- UserPullResultHandler handler = (UserPullResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (UserPullResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultUserPullResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
- handler.setPullExecutor(this);
-
- return handler;
}
protected GroupPullResultHandler buildGroupHandler() {
@@ -245,7 +225,9 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
OperationOptions options = MappingUtils.buildOperationOptions(
MappingUtils.getPullItems(orgUnit.getItems()).iterator());
- rhandler = buildRealmHandler();
+ RealmPullResultHandler handler = buildRealmHandler();
+ handler.setProfile(profile);
+ handler.setPullExecutor(this);
try {
switch (pullTask.getPullMode()) {
@@ -257,7 +239,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
connector.sync(
orgUnit.getObjectClass(),
orgUnit.getSyncToken(),
- rhandler,
+ handler,
options);
if (!dryRun) {
@@ -271,14 +253,14 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
ImplementationManager.build(pullTask.getReconFilterBuilder());
connector.filteredReconciliation(orgUnit.getObjectClass(),
filterBuilder,
- rhandler,
+ handler,
options);
break;
case FULL_RECONCILIATION:
default:
connector.fullReconciliation(orgUnit.getObjectClass(),
- rhandler,
+ handler,
options);
break;
}
@@ -288,18 +270,15 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
}
// ...then provisions for any types
- ahandler = buildAnyObjectHandler();
- uhandler = buildUserHandler();
- ghandler = buildGroupHandler();
-
+ SyncopePullResultHandler handler;
+ GroupPullResultHandler ghandler = buildGroupHandler();
for (Provision provision : pullTask.getResource().getProvisions()) {
if (provision.getMapping() != null) {
status.set("Pulling " + provision.getObjectClass().getObjectClassValue());
- SyncopePullResultHandler handler;
switch (provision.getAnyType().getKind()) {
case USER:
- handler = uhandler;
+ handler = buildUserHandler();
break;
case GROUP:
@@ -308,8 +287,10 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
case ANY_OBJECT:
default:
- handler = ahandler;
+ handler = buildAnyObjectHandler();
}
+ handler.setProfile(profile);
+ handler.setPullExecutor(this);
try {
Set<MappingItem> linkingMappingItems = virSchemaDAO.findByProvision(provision).stream().
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
index 77ca4e1..941e5e4 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
@@ -26,11 +26,10 @@ import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
-import org.apache.syncope.core.persistence.api.dao.AnyDAO;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
@@ -148,10 +147,10 @@ public class PullUtils {
try {
List<String> anyKeys = match(connObj, provision.get(), anyUtils);
if (anyKeys.isEmpty()) {
- LOG.debug("No matching {} found for {}, aborting", anyUtils.getAnyTypeKind(), connObj);
+ LOG.debug("No matching {} found for {}, aborting", anyUtils.anyTypeKind(), connObj);
} else {
if (anyKeys.size() > 1) {
- LOG.warn("More than one {} found {} - taking first only", anyUtils.getAnyTypeKind(), anyKeys);
+ LOG.warn("More than one {} found {} - taking first only", anyUtils.anyTypeKind(), anyKeys);
}
result = Optional.ofNullable(anyKeys.iterator().next());
@@ -164,14 +163,6 @@ public class PullUtils {
return result;
}
- private AnyDAO<?> getAnyDAO(final AnyTypeKind anyTypeKind) {
- return AnyTypeKind.USER == anyTypeKind
- ? userDAO
- : AnyTypeKind.ANY_OBJECT == anyTypeKind
- ? anyObjectDAO
- : groupDAO;
- }
-
private List<String> findByConnObjectKey(
final ConnectorObject connObj, final Provision provision, final AnyUtils anyUtils) {
@@ -213,7 +204,7 @@ public class PullUtils {
if (intAttrName.getField() != null) {
switch (intAttrName.getField()) {
case "key":
- Any<?> any = getAnyDAO(provision.getAnyType().getKind()).find(connObjectKey);
+ Any<?> any = anyUtils.dao().find(connObjectKey);
if (any != null) {
result.add(any.getKey());
}
@@ -256,13 +247,13 @@ public class PullUtils {
}
}
- result.addAll(getAnyDAO(provision.getAnyType().getKind()).
+ result.addAll(anyUtils.dao().
findByPlainAttrValue(intAttrName.getSchemaName(), value).stream().
map(Entity::getKey).collect(Collectors.toList()));
break;
case DERIVED:
- result.addAll(getAnyDAO(provision.getAnyType().getKind()).
+ result.addAll(anyUtils.dao().
findByDerAttrValue(intAttrName.getSchemaName(), connObjectKey).stream().
map(Entity::getKey).collect(Collectors.toList()));
break;
@@ -312,7 +303,7 @@ public class PullUtils {
try {
return rule.isPresent()
- ? findByCorrelationRule(connObj, provision, rule.get(), anyUtils.getAnyTypeKind())
+ ? findByCorrelationRule(connObj, provision, rule.get(), anyUtils.anyTypeKind())
: findByConnObjectKey(connObj, provision, anyUtils);
} catch (RuntimeException e) {
LOG.error("Could not match {} with any existing {}", connObj, provision.getAnyType(), e);
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
index b813e71..2207f42 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
@@ -27,18 +27,15 @@ import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.search.SearchCondConverter;
import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.apache.syncope.core.persistence.api.dao.AnyDAO;
-import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
-import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.group.Group;
@@ -63,41 +60,21 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
/**
- * User DAO.
- */
- @Autowired
- protected UserDAO userDAO;
-
- /**
* Search DAO.
*/
@Autowired
protected AnySearchDAO searchDAO;
- /**
- * Group DAO.
- */
@Autowired
- protected GroupDAO groupDAO;
-
- @Autowired
- protected AnyObjectDAO anyObjectDAO;
+ protected RealmDAO realmDAO;
@Autowired
- protected RealmDAO realmDAO;
+ protected AnyUtilsFactory anyUtilsFactory;
protected ProvisioningProfile<PushTask, PushActions> profile;
protected final Map<String, MutablePair<Integer, String>> handled = new HashMap<>();
- protected RealmPushResultHandler rhandler;
-
- protected AnyObjectPushResultHandler ahandler;
-
- protected UserPushResultHandler uhandler;
-
- protected GroupPushResultHandler ghandler;
-
protected void reportHandled(final String anyType, final String key) {
MutablePair<Integer, String> pair = handled.get(anyType);
if (pair == null) {
@@ -125,25 +102,6 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
return status.get();
}
- protected AnyDAO<?> getAnyDAO(final AnyTypeKind anyTypeKind) {
- AnyDAO<?> result;
- switch (anyTypeKind) {
- case USER:
- result = userDAO;
- break;
-
- case GROUP:
- result = groupDAO;
- break;
-
- case ANY_OBJECT:
- default:
- result = anyObjectDAO;
- }
-
- return result;
- }
-
protected void doHandle(
final List<? extends Any<?>> anys,
final SyncopePushResultHandler handler,
@@ -168,35 +126,23 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
}
protected RealmPushResultHandler buildRealmHandler() {
- RealmPushResultHandler handler = (RealmPushResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (RealmPushResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultRealmPushResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
-
- return handler;
}
protected AnyObjectPushResultHandler buildAnyObjectHandler() {
- AnyObjectPushResultHandler handler = (AnyObjectPushResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (AnyObjectPushResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultAnyObjectPushResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
-
- return handler;
}
protected UserPushResultHandler buildUserHandler() {
- UserPushResultHandler handler = (UserPushResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (UserPushResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultUserPushResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
-
- return handler;
}
protected GroupPushResultHandler buildGroupHandler() {
- GroupPushResultHandler handler = (GroupPushResultHandler) ApplicationContextProvider.getBeanFactory().
+ return (GroupPushResultHandler) ApplicationContextProvider.getBeanFactory().
createBean(DefaultGroupPushResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
- handler.setProfile(profile);
-
- return handler;
}
@Override
@@ -233,13 +179,14 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
if (pushTask.getResource().getOrgUnit() != null) {
status.set("Pushing realms");
- rhandler = buildRealmHandler();
+ RealmPushResultHandler handler = buildRealmHandler();
+ handler.setProfile(profile);
for (Realm realm : realmDAO.findDescendants(profile.getTask().getSourceRealm())) {
// Never push the root realm
if (realm.getParent() != null) {
try {
- rhandler.handle(realm.getKey());
+ handler.handle(realm.getKey());
reportHandled(SyncopeConstants.REALM_ANYTYPE, realm.getName());
} catch (Exception e) {
LOG.warn("Failure pushing '{}' on '{}'", realm, pushTask.getResource(), e);
@@ -250,30 +197,27 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
}
// ...then provisions for any types
- ahandler = buildAnyObjectHandler();
- uhandler = buildUserHandler();
- ghandler = buildGroupHandler();
-
for (Provision provision : pushTask.getResource().getProvisions()) {
if (provision.getMapping() != null) {
status.set("Pushing " + provision.getAnyType().getKey());
- AnyDAO<?> anyDAO = getAnyDAO(provision.getAnyType().getKind());
+ AnyDAO<?> anyDAO = anyUtilsFactory.getInstance(provision.getAnyType().getKind()).dao();
SyncopePushResultHandler handler;
switch (provision.getAnyType().getKind()) {
case USER:
- handler = uhandler;
+ handler = buildUserHandler();
break;
case GROUP:
- handler = ghandler;
+ handler = buildGroupHandler();
break;
case ANY_OBJECT:
default:
- handler = ahandler;
+ handler = buildAnyObjectHandler();
}
+ handler.setProfile(profile);
Optional<? extends PushTaskAnyFilter> anyFilter = pushTask.getFilter(provision.getAnyType());
String filter = anyFilter.isPresent()
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
new file mode 100644
index 0000000..f4f57b4
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
@@ -0,0 +1,174 @@
+/*
+ * 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.provisioning.java.pushpull;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.syncope.common.lib.collections.IteratorChain;
+import org.apache.syncope.common.lib.types.ConflictResolutionAction;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.PullMode;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
+import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.task.PullTask;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.pushpull.GroupPullResultHandler;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
+import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
+import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullResultHandler;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePullExecutor;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
+import org.apache.syncope.core.spring.ImplementationManager;
+import org.identityconnectors.framework.common.objects.AttributeBuilder;
+import org.identityconnectors.framework.common.objects.OperationOptions;
+import org.identityconnectors.framework.common.objects.filter.Filter;
+import org.identityconnectors.framework.common.objects.filter.FilterBuilder;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSinglePullExecutor {
+
+ @Autowired
+ private ImplementationDAO implementationDAO;
+
+ @Override
+ public List<ProvisioningReport> pull(
+ final Provision provision,
+ final Connector connector,
+ final String connObjectKey,
+ final String connObjectValue,
+ final Realm realm,
+ final boolean remediation,
+ final List<String> actionKeys) throws JobExecutionException {
+
+ LOG.debug("Executing pull on {}", provision.getResource());
+
+ List<PullActions> actions = new ArrayList<>();
+ actionKeys.forEach(key -> {
+ Implementation impl = implementationDAO.find(key);
+ if (impl == null || impl.getType() != ImplementationType.PULL_ACTIONS) {
+ LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", key);
+ } else {
+ try {
+ actions.add(ImplementationManager.build(impl));
+ } catch (Exception e) {
+ LOG.warn("While building {}", impl, e);
+ }
+ }
+ });
+
+ try {
+ Set<MappingItem> linkinMappingItems = virSchemaDAO.findByProvision(provision).stream().
+ map(virSchema -> virSchema.asLinkingMappingItem()).collect(Collectors.toSet());
+ Iterator<MappingItem> mapItems = new IteratorChain<>(
+ provision.getMapping().getItems().iterator(),
+ linkinMappingItems.iterator());
+ OperationOptions options = MappingUtils.buildOperationOptions(mapItems);
+
+ PullTask pullTask = entityFactory.newEntity(PullTask.class);
+ pullTask.setResource(provision.getResource());
+ pullTask.setMatchingRule(MatchingRule.UPDATE);
+ pullTask.setUnmatchingRule(UnmatchingRule.PROVISION);
+ pullTask.setPullMode(PullMode.FILTERED_RECONCILIATION);
+ pullTask.setPerformCreate(true);
+ pullTask.setPerformUpdate(true);
+ pullTask.setRemediation(remediation);
+ pullTask.setDestinationRealm(realm);
+
+ profile = new ProvisioningProfile<>(connector, pullTask);
+ profile.setDryRun(false);
+ profile.setResAct(ConflictResolutionAction.FIRSTMATCH);
+ profile.getActions().addAll(actions);
+
+ for (PullActions action : actions) {
+ action.beforeAll(profile);
+ }
+
+ SyncopePullResultHandler handler;
+ GroupPullResultHandler ghandler = buildGroupHandler();
+ switch (provision.getAnyType().getKind()) {
+ case USER:
+ handler = buildUserHandler();
+ break;
+
+ case GROUP:
+ handler = ghandler;
+ break;
+
+ case ANY_OBJECT:
+ default:
+ handler = buildAnyObjectHandler();
+ }
+ handler.setProfile(profile);
+ handler.setPullExecutor(this);
+
+ // execute filtered pull
+ connector.filteredReconciliation(
+ provision.getObjectClass(),
+ new AccountReconciliationFilterBuilder(connObjectKey, connObjectValue),
+ handler,
+ options);
+
+ try {
+ setGroupOwners(ghandler);
+ } catch (Exception e) {
+ LOG.error("While setting group owners", e);
+ }
+
+ for (PullActions action : actions) {
+ action.afterAll(profile);
+ }
+
+ return profile.getResults();
+ } catch (Exception e) {
+ throw e instanceof JobExecutionException
+ ? (JobExecutionException) e
+ : new JobExecutionException("While pulling from connector", e);
+ }
+ }
+
+ class AccountReconciliationFilterBuilder implements ReconFilterBuilder {
+
+ private final String key;
+
+ private final String value;
+
+ AccountReconciliationFilterBuilder(final String key, final String value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public Filter build() {
+ return FilterBuilder.equalTo(AttributeBuilder.build(key, value));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
new file mode 100644
index 0000000..76bdc16
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
@@ -0,0 +1,117 @@
+/*
+ * 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.provisioning.java.pushpull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.task.PushTask;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
+import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopePushResultHandler;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePushExecutor;
+import org.apache.syncope.core.spring.ImplementationManager;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSinglePushExecutor {
+
+ @Autowired
+ private ImplementationDAO implementationDAO;
+
+ @Override
+ public List<ProvisioningReport> push(
+ final Provision provision,
+ final Connector connector,
+ final Any<?> any,
+ final List<String> actionKeys) throws JobExecutionException {
+
+ LOG.debug("Executing push on {}", provision.getResource());
+
+ List<PushActions> actions = new ArrayList<>();
+ actionKeys.forEach(key -> {
+ Implementation impl = implementationDAO.find(key);
+ if (impl == null || impl.getType() != ImplementationType.PUSH_ACTIONS) {
+ LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", key);
+ } else {
+ try {
+ actions.add(ImplementationManager.build(impl));
+ } catch (Exception e) {
+ LOG.warn("While building {}", impl, e);
+ }
+ }
+ });
+
+ try {
+ PushTask pushTask = entityFactory.newEntity(PushTask.class);
+ pushTask.setResource(provision.getResource());
+ pushTask.setMatchingRule(MatchingRule.UPDATE);
+ pushTask.setUnmatchingRule(UnmatchingRule.PROVISION);
+ pushTask.setPerformCreate(true);
+ pushTask.setPerformUpdate(true);
+
+ profile = new ProvisioningProfile<>(connector, pushTask);
+ profile.getActions().addAll(actions);
+ profile.setResAct(null);
+
+ for (PushActions action : actions) {
+ action.beforeAll(profile);
+ }
+
+ SyncopePushResultHandler handler;
+ switch (provision.getAnyType().getKind()) {
+ case USER:
+ handler = buildUserHandler();
+ break;
+
+ case GROUP:
+ handler = buildGroupHandler();
+ break;
+
+ case ANY_OBJECT:
+ default:
+ handler = buildAnyObjectHandler();
+ }
+ handler.setProfile(profile);
+
+ doHandle(Arrays.asList(any), handler, pushTask.getResource());
+
+ for (PushActions action : actions) {
+ action.afterAll(profile);
+ }
+
+ return profile.getResults();
+ } catch (Exception e) {
+ throw e instanceof JobExecutionException
+ ? (JobExecutionException) e
+ : new JobExecutionException("While pushing to connector", e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
index ad9cbed..63e44cb 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
@@ -242,8 +242,8 @@ public class ConnObjectUtils {
updated.setKey(key);
T anyPatch = null;
- if (null != anyUtils.getAnyTypeKind()) {
- switch (anyUtils.getAnyTypeKind()) {
+ if (null != anyUtils.anyTypeKind()) {
+ switch (anyUtils.anyTypeKind()) {
case USER:
UserTO originalUser = (UserTO) original;
UserTO updatedUser = (UserTO) updated;
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
index 92d2aad..9d028e4 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
@@ -64,18 +64,6 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
protected abstract P newPatch(String key);
- protected String getActualKey(final String key) {
- String actualKey = key;
- if (!SyncopeConstants.UUID_PATTERN.matcher(key).matches()) {
- actualKey = getAnyDAO().findKey(key);
- if (actualKey == null) {
- throw new NotFoundException("User, Group or Any Object for " + key);
- }
- }
-
- return actualKey;
- }
-
@Override
public Set<AttrTO> read(final String key, final SchemaType schemaType) {
TO any = read(key);
@@ -124,7 +112,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
@Override
public TO read(final String key) {
- return getAnyLogic().read(getActualKey(key));
+ return getAnyLogic().read(getActualKey(getAnyDAO(), key));
}
@Override
@@ -161,7 +149,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
}
protected Response doUpdate(final P anyPatch) {
- anyPatch.setKey(getActualKey(anyPatch.getKey()));
+ anyPatch.setKey(getActualKey(getAnyDAO(), anyPatch.getKey()));
Date etagDate = findLastChange(anyPatch.getKey());
checkETag(String.valueOf(etagDate.getTime()));
@@ -196,21 +184,23 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
@Override
public Response update(final String key, final SchemaType schemaType, final AttrTO attrTO) {
- String actualKey = getActualKey(key);
+ String actualKey = getActualKey(getAnyDAO(), key);
addUpdateOrReplaceAttr(actualKey, schemaType, attrTO, PatchOperation.ADD_REPLACE);
return modificationResponse(read(actualKey, schemaType, attrTO.getSchema()));
}
@Override
public void delete(final String key, final SchemaType schemaType, final String schema) {
- String actualKey = getActualKey(key);
addUpdateOrReplaceAttr(
- actualKey, schemaType, new AttrTO.Builder().schema(schema).build(), PatchOperation.DELETE);
+ getActualKey(getAnyDAO(), key),
+ schemaType,
+ new AttrTO.Builder().schema(schema).build(),
+ PatchOperation.DELETE);
}
@Override
public Response delete(final String key) {
- String actualKey = getActualKey(key);
+ String actualKey = getActualKey(getAnyDAO(), key);
Date etagDate = findLastChange(actualKey);
checkETag(String.valueOf(etagDate.getTime()));
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractServiceImpl.java
index a040960..caef5d8 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractServiceImpl.java
@@ -37,12 +37,15 @@ import org.apache.cxf.jaxrs.ext.search.SearchCondition;
import org.apache.cxf.jaxrs.ext.search.SearchContext;
import org.apache.syncope.common.lib.AbstractBaseBean;
import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.PagedResult;
import org.apache.syncope.common.lib.to.ProvisioningResult;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.rest.api.service.JAXRSService;
import org.apache.syncope.common.rest.api.Preference;
import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.core.persistence.api.dao.AnyDAO;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.search.SearchCondVisitor;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
@@ -64,6 +67,18 @@ abstract class AbstractServiceImpl implements JAXRSService {
@Context
protected SearchContext searchContext;
+ protected String getActualKey(final AnyDAO<?> dao, final String pretendingKey) {
+ String actualKey = pretendingKey;
+ if (!SyncopeConstants.UUID_PATTERN.matcher(pretendingKey).matches()) {
+ actualKey = dao.findKey(pretendingKey);
+ if (actualKey == null) {
+ throw new NotFoundException("User, Group or Any Object for " + pretendingKey);
+ }
+ }
+
+ return actualKey;
+ }
+
protected boolean isNullPriorityAsync() {
return BooleanUtils.toBoolean(messageContext.getHttpHeaders().getHeaderString(RESTHeaders.NULL_PRIORITY_ASYNC));
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
index 961a328..3a7d40b 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
@@ -71,7 +71,7 @@ public class AnyObjectServiceImpl extends AbstractAnyService<AnyObjectTO, AnyObj
@Override
public Response update(final AnyObjectTO anyObjectTO) {
- anyObjectTO.setKey(getActualKey(anyObjectTO.getKey()));
+ anyObjectTO.setKey(getActualKey(getAnyDAO(), anyObjectTO.getKey()));
AnyObjectTO before = logic.read(anyObjectTO.getKey());
checkETag(before.getETagValue());
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
index 4e23d22..bc621e9 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
@@ -68,7 +68,7 @@ public class GroupServiceImpl extends AbstractAnyService<GroupTO, GroupPatch> im
@Override
public Response update(final GroupTO groupTO) {
- groupTO.setKey(getActualKey(groupTO.getKey()));
+ groupTO.setKey(getActualKey(getAnyDAO(), groupTO.getKey()));
GroupTO before = logic.read(groupTO.getKey());
checkETag(before.getETagValue());
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java
new file mode 100644
index 0000000..80d89d5
--- /dev/null
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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.cxf.service;
+
+import org.apache.syncope.common.lib.to.ReconciliationRequest;
+import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.rest.api.service.ReconciliationService;
+import org.apache.syncope.core.logic.ReconciliationLogic;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ReconciliationServiceImpl extends AbstractServiceImpl implements ReconciliationService {
+
+ @Autowired
+ private ReconciliationLogic logic;
+
+ @Autowired
+ private AnyUtilsFactory anyUtilsFactory;
+
+ @Override
+ public ReconciliationStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
+ return logic.status(
+ anyTypeKind,
+ getActualKey(anyUtilsFactory.getInstance(anyTypeKind).dao(), anyKey),
+ resourceKey);
+ }
+
+ @Override
+ public void reconcile(final ReconciliationRequest request) {
+ request.setAnyKey(
+ getActualKey(anyUtilsFactory.getInstance(request.getAnyTypeKind()).dao(), request.getAnyKey()));
+ logic.reconcile(request);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
index 4af144b..99dc24d 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
@@ -67,7 +67,7 @@ public class UserServiceImpl extends AbstractAnyService<UserTO, UserPatch> imple
@Override
public Response update(final UserTO userTO) {
- userTO.setKey(getActualKey(userTO.getKey()));
+ userTO.setKey(getActualKey(getAnyDAO(), userTO.getKey()));
UserTO before = logic.read(userTO.getKey());
checkETag(before.getETagValue());
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index 3151971..759f5e4 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -85,6 +85,7 @@ import org.apache.syncope.common.rest.api.service.GroupService;
import org.apache.syncope.common.rest.api.service.ImplementationService;
import org.apache.syncope.common.rest.api.service.MailTemplateService;
import org.apache.syncope.common.rest.api.service.RealmService;
+import org.apache.syncope.common.rest.api.service.ReconciliationService;
import org.apache.syncope.common.rest.api.service.RelationshipTypeService;
import org.apache.syncope.common.rest.api.service.RemediationService;
import org.apache.syncope.common.rest.api.service.ReportTemplateService;
@@ -228,6 +229,8 @@ public abstract class AbstractITCase {
protected static TaskService taskService;
+ protected static ReconciliationService reconciliationService;
+
protected static WorkflowService workflowService;
protected static MailTemplateService mailTemplateService;
@@ -307,6 +310,7 @@ public abstract class AbstractITCase {
reportTemplateService = adminClient.getService(ReportTemplateService.class);
reportService = adminClient.getService(ReportService.class);
taskService = adminClient.getService(TaskService.class);
+ reconciliationService = adminClient.getService(ReconciliationService.class);
policyService = adminClient.getService(PolicyService.class);
workflowService = adminClient.getService(WorkflowService.class);
mailTemplateService = adminClient.getService(MailTemplateService.class);
[4/6] syncope git commit: Reworking 'Set admin credentials'
Posted by il...@apache.org.
Reworking 'Set admin credentials'
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/3c4a3515
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/3c4a3515
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/3c4a3515
Branch: refs/heads/master
Commit: 3c4a351534e3221a2ce0f0a9660b442f8dbfdc74
Parents: 3211023
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Apr 12 11:49:28 2018 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Apr 12 11:50:35 2018 +0200
----------------------------------------------------------------------
.../setadmincredentials.adoc | 23 +++++++++++++-------
1 file changed, 15 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/3c4a3515/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/setadmincredentials.adoc
----------------------------------------------------------------------
diff --git a/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/setadmincredentials.adoc b/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/setadmincredentials.adoc
index 4292a06..10e24f0 100644
--- a/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/setadmincredentials.adoc
+++ b/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/setadmincredentials.adoc
@@ -21,22 +21,28 @@
[WARNING]
The procedure below affects only the `Master` <<domains,domain>>; for other domains check <<domains-management,above>>.
-The default password for the `admin` user is `password`.
-
The credentials are defined in the `security.properties` file; text encoding must be set to UTF-8:
-* `adminUser` - administrator username
-* `adminPassword` - SHA1 hash evaluation of cleartext password (represented as a sequence of 40 hexadecimal digits)
-* `adminPasswordAlgorithm` - algorithm to be used for hash evaluation (default value: SHA1)
+* `adminUser` - administrator username (default `admin`)
+* `adminPassword` - administrator password (default `password`)'s hashed value
+* `adminPasswordAlgorithm` - algorithm to be used for hash evaluation (default `SHA1`, others as
+`SHA256`, `SHA512`, `SMD5`, `SSHA1`, `SSHA256`, `SSHA512` and `BCRYPT` are supported)
-For GNU / Linux and Mac OS X, the SHA1 password can be obtained via the `sha1sum` command-line tool of
-http://www.gnu.org/software/coreutils/[GNU Core Utilities^]:
+[TIP]
+====
+The hashed password value can be obtained, depending on the actual algorithm, via various tools.
+As an example, for `SHA1` and GNU / Linux and Mac OS X, the `sha1sum` command-line tool of
+http://www.gnu.org/software/coreutils/[GNU Core Utilities^] can be used as follows:
[source,bash]
....
echo -n "new_password" | sha1sum
....
-For MS Windows, some options are available:
+
+Please beware that any shell special character must be properly escaped for the command above to produce the expected
+hashed value.
+
+Again about `SHA1`, for MS Windows some options are available:
* http://support.microsoft.com/kb/841290[MS File Checksum Integrity Verifier^] +
install, save your password to a file (e.g. `password.txt` without EOL) and issue at command line: +
@@ -47,3 +53,4 @@ fciv.exe -sha1 password.txt
* http://gnuwin32.sourceforge.net/[GnuWin32^] port of GNU utilities for MS Windows
* http://www.cygwin.com/[Cygwin^] Unix-like environment and command-line interface for Microsoft Windows (featuring
http://www.gnu.org/software/coreutils/[GNU Core Utilities^])
+====
[5/6] syncope git commit: [SYNCOPE-1299] Core implementation
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/e5860a76/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java
new file mode 100644
index 0000000..172e69c
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java
@@ -0,0 +1,134 @@
+/*
+ * 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.fit.core;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Date;
+import javax.sql.DataSource;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ReconciliationRequest;
+import org.apache.syncope.common.lib.to.ReconciliationStatus;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ReconciliationAction;
+import org.apache.syncope.fit.AbstractITCase;
+import org.identityconnectors.framework.common.objects.OperationalAttributes;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+
+@SpringJUnitConfig(locations = { "classpath:testJDBCEnv.xml" })
+public class ReconciliationITCase extends AbstractITCase {
+
+ @Autowired
+ private DataSource testDataSource;
+
+ @Test
+ public void push() {
+ // 1. create printer, with no resources
+ AnyObjectTO printer = AnyObjectITCase.getSampleTO("reconciliation");
+ printer.getResources().clear();
+ printer = createAnyObject(printer).getEntity();
+ assertNotNull(printer.getKey());
+
+ // 2. verify no printer with that name is on the external resource's db
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
+ assertEquals(0, jdbcTemplate.queryForList(
+ "SELECT id FROM testPRINTER WHERE printername=?", printer.getName()).size());
+
+ // 3. verify reconciliation status
+ ReconciliationStatus status =
+ reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
+ assertNotNull(status);
+ assertNotNull(status.getOnSyncope());
+ assertNull(status.getOnResource());
+
+ // 4. push
+ ReconciliationRequest request = new ReconciliationRequest();
+ request.setAction(ReconciliationAction.PUSH);
+ request.setAnyKey(printer.getKey());
+ request.setAnyTypeKind(AnyTypeKind.ANY_OBJECT);
+ request.setResourceKey("resource-db-scripted");
+ reconciliationService.reconcile(request);
+
+ // 5. verify that printer is now propagated
+ assertEquals(1, jdbcTemplate.queryForList(
+ "SELECT id FROM testPRINTER WHERE printername=?", printer.getName()).size());
+
+ // 6. verify resource was not assigned
+ printer = anyObjectService.read(printer.getKey());
+ assertTrue(printer.getResources().isEmpty());
+
+ // 7. verify reconciliation status
+ status = reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
+ assertNotNull(status);
+ assertNotNull(status.getOnSyncope());
+ assertNotNull(status.getOnResource());
+
+ // __ENABLE__ management depends on the actual connector...
+ AttrTO enable = status.getOnSyncope().getAttr(OperationalAttributes.ENABLE_NAME).orElse(null);
+ if (enable != null) {
+ status.getOnSyncope().getAttrs().remove(enable);
+ }
+ assertEquals(status.getOnSyncope(), status.getOnResource());
+ }
+
+ @Test
+ public void pull() {
+ // 1. create printer, with no resources
+ AnyObjectTO printer = AnyObjectITCase.getSampleTO("reconciliation");
+ printer.getResources().clear();
+ printer = createAnyObject(printer).getEntity();
+ assertNotNull(printer.getKey());
+ assertNotEquals("Nowhere", printer.getPlainAttr("location").get().getValues().get(0));
+
+ // 2. create table into the external resource's db, with same name
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
+ jdbcTemplate.update(
+ "INSERT INTO TESTPRINTER (id, printername, location, deleted, lastmodification) VALUES (?,?,?,?,?)",
+ printer.getKey(), printer.getName(), "Nowhere", false, new Date());
+
+ // 3. verify reconciliation status
+ ReconciliationStatus status =
+ reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
+ assertNotNull(status);
+ assertNotNull(status.getOnSyncope());
+ assertNotNull(status.getOnResource());
+ assertNotEquals(status.getOnSyncope().getAttr("LOCATION"), status.getOnResource().getAttr("LOCATION"));
+
+ // 4. pull
+ ReconciliationRequest request = new ReconciliationRequest();
+ request.setAction(ReconciliationAction.PULL);
+ request.setAnyKey(printer.getKey());
+ request.setAnyTypeKind(AnyTypeKind.ANY_OBJECT);
+ request.setResourceKey("resource-db-scripted");
+ reconciliationService.reconcile(request);
+
+ // 5. verify reconciliation result (and resource is still not assigned)
+ printer = anyObjectService.read(printer.getKey());
+ assertEquals("Nowhere", printer.getPlainAttr("location").get().getValues().get(0));
+ assertTrue(printer.getResources().isEmpty());
+ }
+}