syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [2/2] syncope git commit: [SYNCOPE-1287] Core implementation
Date Wed, 28 Mar 2018 14:53:27 GMT
[SYNCOPE-1287] Core implementation


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/51b314fe
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/51b314fe
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/51b314fe

Branch: refs/heads/master
Commit: 51b314fe514695a79b3f0e39e8b1f06dd49dbebc
Parents: 59a3422
Author: Francesco Chicchiriccò <ilgrosso@apache.org>
Authored: Wed Mar 28 16:53:12 2018 +0200
Committer: Francesco Chicchiriccò <ilgrosso@apache.org>
Committed: Wed Mar 28 16:53:12 2018 +0200

----------------------------------------------------------------------
 .../console/tasks/SchedTaskWizardBuilder.java   |   6 +-
 .../tasks/SchedTaskWizardBuilder$Profile.html   |   1 +
 .../SchedTaskWizardBuilder$Profile.properties   |   1 +
 ...SchedTaskWizardBuilder$Profile_it.properties |   1 +
 ...SchedTaskWizardBuilder$Profile_ja.properties |   1 +
 ...edTaskWizardBuilder$Profile_pt_BR.properties |   1 +
 ...SchedTaskWizardBuilder$Profile_ru.properties |   1 +
 .../syncope/common/lib/to/PullTaskTO.java       |  11 +
 .../syncope/common/lib/to/RemediationTO.java    | 165 ++++++++++++++
 .../syncope/common/lib/types/AnyTypeKind.java   |  19 +-
 .../common/lib/types/EntityViolationType.java   |  12 ++
 .../common/lib/types/StandardEntitlement.java   |   8 +
 .../rest/api/service/ImplementationService.java |   6 +-
 .../rest/api/service/RemediationService.java    | 213 +++++++++++++++++++
 .../common/rest/api/service/UserService.java    |  27 +--
 .../syncope/core/logic/AccessTokenLogic.java    |   2 +-
 .../syncope/core/logic/AnyTypeClassLogic.java   |   3 +-
 .../apache/syncope/core/logic/AnyTypeLogic.java |   2 +-
 .../syncope/core/logic/ApplicationLogic.java    |   3 +-
 .../core/logic/ConnectorHistoryLogic.java       |  16 +-
 .../syncope/core/logic/ConnectorLogic.java      |  49 ++---
 .../apache/syncope/core/logic/DomainLogic.java  |   5 +-
 .../syncope/core/logic/DynRealmLogic.java       |   6 +-
 .../syncope/core/logic/ImplementationLogic.java |   6 +-
 .../apache/syncope/core/logic/LoggerLogic.java  |   2 +
 .../syncope/core/logic/MailTemplateLogic.java   |   3 +
 .../syncope/core/logic/NotificationLogic.java   |   6 +-
 .../apache/syncope/core/logic/PolicyLogic.java  |   5 +-
 .../apache/syncope/core/logic/RealmLogic.java   |   2 +
 .../core/logic/RelationshipTypeLogic.java       |   6 +-
 .../syncope/core/logic/RemediationLogic.java    | 210 ++++++++++++++++++
 .../apache/syncope/core/logic/ReportLogic.java  |   5 +-
 .../syncope/core/logic/ReportTemplateLogic.java |   3 +
 .../core/logic/ResourceHistoryLogic.java        |  16 +-
 .../syncope/core/logic/ResourceLogic.java       |   3 +-
 .../apache/syncope/core/logic/RoleLogic.java    |   2 +-
 .../apache/syncope/core/logic/SchemaLogic.java  |   3 +
 .../core/logic/SecurityQuestionLogic.java       |   3 +-
 .../apache/syncope/core/logic/SyncopeLogic.java |  14 +-
 .../apache/syncope/core/logic/TaskLogic.java    |   3 +
 .../syncope/core/logic/UserWorkflowLogic.java   |   6 +-
 .../validation/InvalidEntityException.java      |   2 +
 .../persistence/api/dao/RemediationDAO.java     |  39 ++++
 .../persistence/api/entity/Remediation.java     |  65 ++++++
 .../persistence/api/entity/task/PullTask.java   |   5 +
 .../persistence/jpa/dao/JPARemediationDAO.java  |  73 +++++++
 .../core/persistence/jpa/dao/JPATaskDAO.java    |  11 +
 .../jpa/entity/JPAEntityFactory.java            |   3 +
 .../persistence/jpa/entity/JPARemediation.java  | 171 +++++++++++++++
 .../jpa/entity/task/JPAPullTask.java            |  18 ++
 .../jpa/validation/entity/RemediationCheck.java |  41 ++++
 .../validation/entity/RemediationValidator.java |  80 +++++++
 .../persistence/jpa/inner/RemediationTest.java  | 103 +++++++++
 .../api/data/ConnInstanceDataBinder.java        |   4 +
 .../api/data/RemediationDataBinder.java         |  28 +++
 .../api/data/ResourceDataBinder.java            |   3 +
 .../java/data/ConnInstanceDataBinderImpl.java   |  12 ++
 .../java/data/RemediationDataBinderImpl.java    |  65 ++++++
 .../java/data/ResourceDataBinderImpl.java       |  12 ++
 .../java/data/TaskDataBinderImpl.java           |   4 +
 .../pushpull/AbstractPullResultHandler.java     |  52 ++++-
 .../cxf/service/RemediationServiceImpl.java     | 116 ++++++++++
 .../org/apache/syncope/fit/AbstractITCase.java  |   4 +
 .../syncope/fit/core/AbstractTaskITCase.java    |  36 ++--
 .../apache/syncope/fit/core/PullTaskITCase.java |  84 ++++++++
 65 files changed, 1755 insertions(+), 133 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
index 8efd140..a23f39b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
@@ -240,8 +240,12 @@ public class SchedTaskWizardBuilder<T extends SchedTaskTO> extends AjaxWizardBui
             destinationRealm.setNullValid(!(taskTO instanceof PullTaskTO));
             pullTaskSpecifics.add(destinationRealm);
 
+            AjaxCheckBoxPanel remediation = new AjaxCheckBoxPanel(
+                    "remediation", "remediation", new PropertyModel<>(taskTO, "remediation"), false);
+            pullTaskSpecifics.add(remediation);
+
             // ------------------------------
-            // Only for pull tasks
+            // Only for push tasks
             // ------------------------------  
             WebMarkupContainer pushTaskSpecifics = new WebMarkupContainer("pushTaskSpecifics");
             add(pushTaskSpecifics.setRenderBodyOnly(true));

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile.html b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile.html
index d45da13..4eabfb5 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile.html
@@ -28,6 +28,7 @@ under the License.
       <div class="form-group"><span wicket:id="destinationRealm">[destinationRealm]</span></div>
       <div class="form-group"><span wicket:id="pullMode">[pullMode]</span></div>
       <div class="form-group"><span wicket:id="reconFilterBuilder">[filter]</span></div>
+      <div class="form-group"><span wicket:id="remediation">[remediation]</span></div>
     </span>      
 
     <span wicket:id="pushTaskSpecifics">

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile.properties b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile.properties
index 8200501..2acbca2 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile.properties
@@ -31,3 +31,4 @@ edit=Edit
 execute=Execute
 executeDryRun=Dry run
 latestExecStatus=Last status
+remediation=Remediation

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_it.properties
index 5cddafd..bc2c4bd 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_it.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_it.properties
@@ -31,3 +31,4 @@ edit=Edit
 execute=Execute
 executeDryRun=Dry run
 latestExecStatus=Last status
+remediation=Remediation

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_ja.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_ja.properties b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_ja.properties
index b1b725c..1204172 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_ja.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_ja.properties
@@ -31,3 +31,4 @@ edit=\u7de8\u96c6
 execute=\u5b9f\u884c
 executeDryRun=\u4e88\u884c\u6f14\u7fd2
 latestExecStatus=\u6700\u7d42\u30b9\u30c6\u30fc\u30bf\u30b9
+remediation=Remediation

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_pt_BR.properties
index 8200501..2acbca2 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_pt_BR.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_pt_BR.properties
@@ -31,3 +31,4 @@ edit=Edit
 execute=Execute
 executeDryRun=Dry run
 latestExecStatus=Last status
+remediation=Remediation

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_ru.properties
index 3b79aad..18bbca6 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_ru.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder$Profile_ru.properties
@@ -32,3 +32,4 @@ edit=\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c
 execute=\u0417\u0430\u043f\u0443\u0441\u043a
 executeDryRun=\u041f\u0440\u043e\u0431\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a
 latestExecStatus=\u0421\u0442\u0430\u0442\u0443\u0441 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430
+remediation=Remediation

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/common/lib/src/main/java/org/apache/syncope/common/lib/to/PullTaskTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/PullTaskTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/PullTaskTO.java
index 2638ad6..3981200 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/PullTaskTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/PullTaskTO.java
@@ -50,6 +50,8 @@ public class PullTaskTO extends ProvisioningTaskTO implements TemplatableTO {
     @XmlElement(required = true)
     private String destinationRealm;
 
+    private boolean remediation;
+
     @XmlTransient
     @JsonProperty("@class")
     @Schema(name = "@class", required = true, example = "org.apache.syncope.common.lib.to.PullTaskTO")
@@ -90,4 +92,13 @@ public class PullTaskTO extends ProvisioningTaskTO implements TemplatableTO {
     public Map<String, AnyTO> getTemplates() {
         return templates;
     }
+
+    public boolean isRemediation() {
+        return remediation;
+    }
+
+    public void setRemediation(final boolean remediation) {
+        this.remediation = remediation;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/common/lib/src/main/java/org/apache/syncope/common/lib/to/RemediationTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RemediationTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RemediationTO.java
new file mode 100644
index 0000000..0b971cd
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RemediationTO.java
@@ -0,0 +1,165 @@
+/*
+ * 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 java.util.Date;
+import javax.ws.rs.PathParam;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.patch.AnyPatch;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+
+@XmlRootElement(name = "remediation")
+@XmlType
+public class RemediationTO extends AbstractBaseBean implements EntityTO {
+
+    private static final long serialVersionUID = 3983540425142284975L;
+
+    private String key;
+
+    private AnyTypeKind anyTypeKind;
+
+    private ResourceOperation operation;
+
+    private AnyTO anyTOPayload;
+
+    private AnyPatch anyPatchPayload;
+
+    private String keyPayload;
+
+    private String error;
+
+    private Date instant;
+
+    private String pullTask;
+
+    private String resource;
+
+    private String remoteName;
+
+    @Override
+    public String getKey() {
+        return key;
+    }
+
+    @PathParam("key")
+    @Override
+    public void setKey(final String key) {
+        this.key = key;
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+    public AnyTypeKind getAnyTypeKind() {
+        return anyTypeKind;
+    }
+
+    public void setAnyTypeKind(final AnyTypeKind anyTypeKind) {
+        this.anyTypeKind = anyTypeKind;
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+    public ResourceOperation getOperation() {
+        return operation;
+    }
+
+    public void setOperation(final ResourceOperation operation) {
+        this.operation = operation;
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+    public AnyTO getAnyTOPayload() {
+        return anyTOPayload;
+    }
+
+    public void setAnyTOPayload(final AnyTO anyTOPayload) {
+        this.anyTOPayload = anyTOPayload;
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+    public AnyPatch getAnyPatchPayload() {
+        return anyPatchPayload;
+    }
+
+    public void setAnyPatchPayload(final AnyPatch anyPatchPayload) {
+        this.anyPatchPayload = anyPatchPayload;
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+    public String getKeyPayload() {
+        return keyPayload;
+    }
+
+    public void setKeyPayload(final String keyPayload) {
+        this.keyPayload = keyPayload;
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+    public String getError() {
+        return error;
+    }
+
+    public void setError(final String error) {
+        this.error = error;
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+    public Date getInstant() {
+        return instant == null
+                ? null
+                : new Date(instant.getTime());
+    }
+
+    public void setInstant(final Date instant) {
+        this.instant = instant == null
+                ? null
+                : new Date(instant.getTime());
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+    public String getPullTask() {
+        return pullTask;
+    }
+
+    public void setPullTask(final String pullTask) {
+        this.pullTask = pullTask;
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+    public String getResource() {
+        return resource;
+    }
+
+    public void setResource(final String resource) {
+        this.resource = resource;
+    }
+
+    @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+
+    public String getRemoteName() {
+        return remoteName;
+    }
+
+    public void setRemoteName(final String remoteName) {
+        this.remoteName = remoteName;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java
index 12fbf59..6cd6c98 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java
@@ -19,6 +19,10 @@
 package org.apache.syncope.common.lib.types;
 
 import javax.xml.bind.annotation.XmlEnum;
+import org.apache.syncope.common.lib.patch.AnyObjectPatch;
+import org.apache.syncope.common.lib.patch.AnyPatch;
+import org.apache.syncope.common.lib.patch.GroupPatch;
+import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.GroupTO;
@@ -27,18 +31,25 @@ import org.apache.syncope.common.lib.to.UserTO;
 @XmlEnum
 public enum AnyTypeKind {
 
-    USER(UserTO.class),
-    GROUP(GroupTO.class),
-    ANY_OBJECT(AnyObjectTO.class);
+    USER(UserTO.class, UserPatch.class),
+    GROUP(GroupTO.class, GroupPatch.class),
+    ANY_OBJECT(AnyObjectTO.class, AnyObjectPatch.class);
 
     private final Class<? extends AnyTO> toClass;
 
-    AnyTypeKind(final Class<? extends AnyTO> toClass) {
+    private final Class<? extends AnyPatch> patchClass;
+
+    AnyTypeKind(final Class<? extends AnyTO> toClass, final Class<? extends AnyPatch> patchClass) {
         this.toClass = toClass;
+        this.patchClass = patchClass;
     }
 
     public Class<? extends AnyTO> getTOClass() {
         return toClass;
     }
 
+    public Class<? extends AnyPatch> getPatchClass() {
+        return patchClass;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
index 6cc7e7c..462ee5f 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
@@ -47,10 +47,13 @@ public enum EntityViolationType {
     InvalidPlainAttr("org.apache.syncope.core.persistence.validation.plainattr"),
     InvalidUsername("org.apache.syncope.core.persistence.validation.user.username"),
     InvalidValueList("org.apache.syncope.core.persistence.validation.attr.valueList"),
+    InvalidRemediation("org.apache.syncope.core.persistence.validation.remediation"),
     MoreThanOneNonNull("org.apache.syncope.core.persistence.validation.attrvalue.moreThanOneNonNull");
 
     private String message;
 
+    private String propertyPath;
+
     EntityViolationType(final String message) {
         this.message = message;
     }
@@ -62,4 +65,13 @@ public enum EntityViolationType {
     public String getMessage() {
         return message;
     }
+
+    public String getPropertyPath() {
+        return propertyPath;
+    }
+
+    public void setPropertyPath(final String propertyPath) {
+        this.propertyPath = propertyPath;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/common/lib/src/main/java/org/apache/syncope/common/lib/types/StandardEntitlement.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/StandardEntitlement.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/StandardEntitlement.java
index 00a6638..0968f34 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/StandardEntitlement.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/StandardEntitlement.java
@@ -302,6 +302,14 @@ public final class StandardEntitlement {
 
     public static final String IMPLEMENTATION_DELETE = "IMPLEMENTATION_DELETE";
 
+    public static final String REMEDIATION_LIST = "REMEDIATION_LIST";
+
+    public static final String REMEDIATION_READ = "REMEDIATION_READ";
+
+    public static final String REMEDIATION_REMEDY = "REMEDIATION_REMEDY";
+
+    public static final String REMEDIATION_DELETE = "REMEDIATION_DELETE";
+
     private static final Set<String> VALUES;
 
     static {

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ImplementationService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ImplementationService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ImplementationService.java
index 620d3fc..cf6352e 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ImplementationService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ImplementationService.java
@@ -47,7 +47,7 @@ import org.apache.syncope.common.lib.types.ImplementationType;
 public interface ImplementationService extends JAXRSService {
 
     /**
-     * Returns a list of all implementations.
+     * Returns a list of all implementations of the given type.
      *
      * @param type implementation type
      * @return list of all implementations.
@@ -58,7 +58,7 @@ public interface ImplementationService extends JAXRSService {
     List<ImplementationTO> list(@NotNull @PathParam("type") ImplementationType type);
 
     /**
-     * Returns implementation with matching key.
+     * Returns implementation with matching type and key.
      *
      * @param type implementation type
      * @param key key of implementation to be read
@@ -94,7 +94,7 @@ public interface ImplementationService extends JAXRSService {
     Response update(@NotNull ImplementationTO implementationTO);
 
     /**
-     * Deletes the implementation matching the given key.
+     * Deletes the implementation matching the given key and type.
      *
      * @param type implementation type
      * @param key key for implementation to be deleted

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RemediationService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RemediationService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RemediationService.java
new file mode 100644
index 0000000..936eca5
--- /dev/null
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RemediationService.java
@@ -0,0 +1,213 @@
+/*
+ * 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.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.headers.Header;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 java.util.List;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PATCH;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.patch.AnyPatch;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.ProvisioningResult;
+import org.apache.syncope.common.lib.to.RemediationTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+
+/**
+ * REST operations for remediations.
+ */
+@Tag(name = "Remediations")
+@SecurityRequirements({
+    @SecurityRequirement(name = "BasicAuthentication"),
+    @SecurityRequirement(name = "Bearer") })
+@Path("remediations")
+public interface RemediationService extends JAXRSService {
+
+    /**
+     * Returns a list of all remediations.
+     *
+     * @return list of all remediations.
+     */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    List<RemediationTO> list();
+
+    /**
+     * Returns remediation with matching key.
+     *
+     * @param key key of remediation to be read
+     * @return remediation with matching key
+     */
+    @GET
+    @Path("{key}")
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    RemediationTO read(@NotNull @PathParam("key") String key);
+
+    /**
+     * Deletes the remediation matching the given key.
+     *
+     * @param key key for remediation to be deleted
+     * @return an empty response if operation was successful
+     */
+    @DELETE
+    @Path("{key}")
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    Response delete(@NotNull @PathParam("key") String key);
+
+    /**
+     * Perform remediation by creating the provided user, group or any object.
+     *
+     * @param key key for remediation to act on
+     * @param anyTO user, group or any object to create
+     * @return Response object featuring Location header of created object as well as the object itself
+     * enriched with propagation status information
+     */
+    @Parameter(name = RESTHeaders.PREFER, in = ParameterIn.HEADER,
+            description = "Allows client to specify a preference for the result to be returned from the server",
+            allowEmptyValue = true, schema =
+            @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = RESTHeaders.NULL_PRIORITY_ASYNC, in = ParameterIn.HEADER,
+            description = "If 'true', instructs the propagation process not to wait for completion when communicating"
+            + " with External Resources with no priority set",
+            allowEmptyValue = true, schema =
+            @Schema(type = "boolean", defaultValue = "false"))
+    @ApiResponses(
+            @ApiResponse(responseCode = "201",
+                    description = "Object successfully created enriched with propagation status information, as Entity,"
+                    + "or empty if 'Prefer: return-no-content' was specified",
+                    content =
+                    @Content(schema =
+                            @Schema(implementation = ProvisioningResult.class)), headers = {
+                @Header(name = RESTHeaders.RESOURCE_KEY, schema =
+                        @Schema(type = "string"),
+                        description = "UUID generated for the object created"),
+                @Header(name = HttpHeaders.LOCATION, schema =
+                        @Schema(type = "string"),
+                        description = "URL of the object created"),
+                @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
+                        @Schema(type = "string"),
+                        description = "Allows the server to inform the "
+                        + "client about the fact that a specified preference was applied") }))
+    @POST
+    @Path("{key}")
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    Response remedy(@NotNull @PathParam("key") String key, @NotNull AnyTO anyTO);
+
+    /**
+     * Perform remediation by updating the provided user, group or any object.
+     *
+     * @param key key for remediation to act on
+     * @param anyPatch user, group or any object to update
+     * @return Response object featuring the updated object enriched with propagation status information
+     */
+    @Parameter(name = RESTHeaders.PREFER, in = ParameterIn.HEADER,
+            description = "Allows client to specify a preference for the result to be returned from the server",
+            allowEmptyValue = true, schema =
+            @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
+    @Parameter(name = RESTHeaders.NULL_PRIORITY_ASYNC, in = ParameterIn.HEADER,
+            description = "If 'true', instructs the propagation process not to wait for completion when communicating"
+            + " with External Resources with no priority set",
+            allowEmptyValue = true, schema =
+            @Schema(type = "boolean", defaultValue = "false"))
+    @ApiResponses({
+        @ApiResponse(responseCode = "200",
+                description = "Object successfully updated enriched with propagation status information, as Entity",
+                content =
+                @Content(schema =
+                        @Schema(implementation = ProvisioningResult.class))),
+        @ApiResponse(responseCode = "204",
+                description = "No content if 'Prefer: return-no-content' was specified", headers =
+                @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
+                        @Schema(type = "string"),
+                        description = "Allows the server to inform the "
+                        + "client about the fact that a specified preference was applied")),
+        @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
+    @PATCH
+    @Path("{key}")
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    Response remedy(@NotNull @PathParam("key") String key, @NotNull AnyPatch anyPatch);
+
+    /**
+     * Perform remediation by deleting the provided user, group or any object.
+     *
+     * @param key key for remediation to act on
+     * @param anyKey user's, group's or any object's key to delete
+     * @return Response object featuring the deleted object enriched with propagation status information
+     */
+    @Parameter(name = RESTHeaders.PREFER, in = ParameterIn.HEADER,
+            description = "Allows client to specify a preference for the result to be returned from the server",
+            allowEmptyValue = true, schema =
+            @Schema(defaultValue = "return-content", allowableValues = { "return-content", "return-no-content" }))
+    @Parameter(name = HttpHeaders.IF_MATCH, in = ParameterIn.HEADER,
+            description = "When the provided ETag value does not match the latest modification date of the entity, "
+            + "an error is reported and the requested operation is not performed.",
+            allowEmptyValue = true, schema =
+            @Schema(type = "string"))
+    @Parameter(name = RESTHeaders.NULL_PRIORITY_ASYNC, in = ParameterIn.HEADER,
+            description = "If 'true', instructs the propagation process not to wait for completion when communicating"
+            + " with External Resources with no priority set",
+            allowEmptyValue = true, schema =
+            @Schema(type = "boolean", defaultValue = "false"))
+    @ApiResponses({
+        @ApiResponse(responseCode = "200",
+                description = "Object successfully deleted enriched with propagation status information, as Entity",
+                content =
+                @Content(schema =
+                        @Schema(implementation = ProvisioningResult.class))),
+        @ApiResponse(responseCode = "204",
+                description = "No content if 'Prefer: return-no-content' was specified", headers =
+                @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
+                        @Schema(type = "string"),
+                        description = "Allows the server to inform the "
+                        + "client about the fact that a specified preference was applied")),
+        @ApiResponse(responseCode = "412",
+                description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
+                + " date of the entity") })
+    @DELETE
+    @Path("{key}/{anyKey}")
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    Response remedy(@NotNull @PathParam("key") String key, @NotNull String anyKey);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
index 3bb0148..7a52fa5 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
@@ -53,8 +53,7 @@ import org.apache.syncope.common.rest.api.beans.AnyQuery;
  */
 @Tag(name = "Users")
 @SecurityRequirements({
-    @SecurityRequirement(name = "BasicAuthentication")
-    ,
+    @SecurityRequirement(name = "BasicAuthentication"),
     @SecurityRequirement(name = "Bearer") })
 @Path("users")
 public interface UserService extends AnyService<UserTO> {
@@ -99,12 +98,10 @@ public interface UserService extends AnyService<UserTO> {
                             @Schema(implementation = ProvisioningResult.class)), headers = {
                 @Header(name = RESTHeaders.RESOURCE_KEY, schema =
                         @Schema(type = "string"),
-                        description = "UUID generated for the user created")
-                ,
+                        description = "UUID generated for the user created"),
                 @Header(name = HttpHeaders.LOCATION, schema =
                         @Schema(type = "string"),
-                        description = "URL of the user created")
-                ,
+                        description = "URL of the user created"),
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
@@ -141,15 +138,13 @@ public interface UserService extends AnyService<UserTO> {
                 description = "User successfully updated enriched with propagation status information, as Entity",
                 content =
                 @Content(schema =
-                        @Schema(implementation = ProvisioningResult.class)))
-        ,
+                        @Schema(implementation = ProvisioningResult.class))),
         @ApiResponse(responseCode = "204",
                 description = "No content if 'Prefer: return-no-content' was specified", headers =
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied"))
-        ,
+                        + "client about the fact that a specified preference was applied")),
         @ApiResponse(responseCode = "412",
                 description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
                 + " date of the entity") })
@@ -185,15 +180,13 @@ public interface UserService extends AnyService<UserTO> {
                 description = "User successfully updated enriched with propagation status information, as Entity",
                 content =
                 @Content(schema =
-                        @Schema(implementation = ProvisioningResult.class)))
-        ,
+                        @Schema(implementation = ProvisioningResult.class))),
         @ApiResponse(responseCode = "204",
                 description = "No content if 'Prefer: return-no-content' was specified", headers =
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied"))
-        ,
+                        + "client about the fact that a specified preference was applied")),
         @ApiResponse(responseCode = "412",
                 description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
                 + " date of the entity") })
@@ -229,15 +222,13 @@ public interface UserService extends AnyService<UserTO> {
                 description = "User successfully updated enriched with propagation status information, as Entity",
                 content =
                 @Content(schema =
-                        @Schema(implementation = ProvisioningResult.class)))
-        ,
+                        @Schema(implementation = ProvisioningResult.class))),
         @ApiResponse(responseCode = "204",
                 description = "No content if 'Prefer: return-no-content' was specified", headers =
                 @Header(name = RESTHeaders.PREFERENCE_APPLIED, schema =
                         @Schema(type = "string"),
                         description = "Allows the server to inform the "
-                        + "client about the fact that a specified preference was applied"))
-        ,
+                        + "client about the fact that a specified preference was applied")),
         @ApiResponse(responseCode = "412",
                 description = "The ETag value provided via the 'If-Match' header does not match the latest modification"
                 + " date of the entity") })

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/AccessTokenLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AccessTokenLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AccessTokenLogic.java
index aa71fbd..0c00b45 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AccessTokenLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AccessTokenLogic.java
@@ -113,7 +113,7 @@ public class AccessTokenLogic extends AbstractTransactionalLogic<AccessTokenTO>
         Integer count = accessTokenDAO.count();
 
         List<AccessTokenTO> result = accessTokenDAO.findAll(page, size, orderByClauses).stream().
-                map(accessToken -> binder.getAccessTokenTO(accessToken)).collect(Collectors.toList());
+                map(binder::getAccessTokenTO).collect(Collectors.toList());
 
         return Pair.of(count, result);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeClassLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeClassLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeClassLogic.java
index 03f6909..adab632 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeClassLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeClassLogic.java
@@ -62,8 +62,7 @@ public class AnyTypeClassLogic extends AbstractTransactionalLogic<AnyTypeClassTO
     @PreAuthorize("hasRole('" + StandardEntitlement.ANYTYPECLASS_LIST + "')")
     @Transactional(readOnly = true)
     public List<AnyTypeClassTO> list() {
-        return anyTypeClassDAO.findAll().stream().
-                map(anyTypeClass -> binder.getAnyTypeClassTO(anyTypeClass)).collect(Collectors.toList());
+        return anyTypeClassDAO.findAll().stream().map(binder::getAnyTypeClassTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.ANYTYPECLASS_CREATE + "')")

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
index 95944c9..d606af2 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
@@ -66,7 +66,7 @@ public class AnyTypeLogic extends AbstractTransactionalLogic<AnyTypeTO> {
     @PreAuthorize("hasRole('" + StandardEntitlement.ANYTYPE_LIST + "')")
     @Transactional(readOnly = true)
     public List<AnyTypeTO> list() {
-        return anyTypeDAO.findAll().stream().map(anyType -> binder.getAnyTypeTO(anyType)).collect(Collectors.toList());
+        return anyTypeDAO.findAll().stream().map(binder::getAnyTypeTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.ANYTYPE_CREATE + "')")

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/ApplicationLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ApplicationLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ApplicationLogic.java
index e25f532..50495ca 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ApplicationLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ApplicationLogic.java
@@ -73,8 +73,7 @@ public class ApplicationLogic extends AbstractTransactionalLogic<ApplicationTO>
     @PreAuthorize("hasRole('" + StandardEntitlement.APPLICATION_LIST + "')")
     @Transactional(readOnly = true)
     public List<ApplicationTO> list() {
-        return applicationDAO.findAll().stream().
-                map(application -> binder.getApplicationTO(application)).collect(Collectors.toList());
+        return applicationDAO.findAll().stream().map(binder::getApplicationTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.APPLICATION_CREATE + "')")

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorHistoryLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorHistoryLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorHistoryLogic.java
index e7ff07c..e3a22a8 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorHistoryLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorHistoryLogic.java
@@ -32,6 +32,7 @@ import org.apache.syncope.core.provisioning.api.data.ConnInstanceDataBinder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class ConnectorHistoryLogic extends AbstractTransactionalLogic<ConnInstanceHistoryConfTO> {
@@ -45,17 +46,8 @@ public class ConnectorHistoryLogic extends AbstractTransactionalLogic<ConnInstan
     @Autowired
     private ConnInstanceDataBinder binder;
 
-    private ConnInstanceHistoryConfTO getConnInstanceHistoryConfTO(final ConnInstanceHistoryConf history) {
-        ConnInstanceHistoryConfTO historyTO = new ConnInstanceHistoryConfTO();
-        historyTO.setKey(history.getKey());
-        historyTO.setCreator(history.getCreator());
-        historyTO.setCreation(history.getCreation());
-        historyTO.setConnInstanceTO(history.getConf());
-
-        return historyTO;
-    }
-
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_HISTORY_LIST + "')")
+    @Transactional(readOnly = true)
     public List<ConnInstanceHistoryConfTO> list(final String key) {
         ConnInstance connInstance = connInstanceDAO.find(key);
         if (connInstance == null) {
@@ -63,7 +55,7 @@ public class ConnectorHistoryLogic extends AbstractTransactionalLogic<ConnInstan
         }
 
         return connInstanceHistoryConfDAO.findByEntity(connInstance).stream().
-                map(historyConf -> getConnInstanceHistoryConfTO(historyConf)).collect(Collectors.toList());
+                map(binder::getConnInstanceHistoryConfTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_HISTORY_RESTORE + "')")
@@ -93,7 +85,7 @@ public class ConnectorHistoryLogic extends AbstractTransactionalLogic<ConnInstan
         if (!"list".equals(method.getName())) {
             try {
                 String key = (String) args[0];
-                return getConnInstanceHistoryConfTO(connInstanceHistoryConfDAO.find(key));
+                return binder.getConnInstanceHistoryConfTO(connInstanceHistoryConfDAO.find(key));
             } catch (Throwable ignore) {
                 LOG.debug("Unresolved reference", ignore);
                 throw new UnresolvedReferenceException(ignore);

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
index 75d704e..c5bbdf8 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
@@ -19,11 +19,9 @@
 package org.apache.syncope.core.logic;
 
 import java.lang.reflect.Method;
-import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.ArrayUtils;
@@ -47,8 +45,8 @@ import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.identityconnectors.common.l10n.CurrentLocale;
 import org.identityconnectors.framework.api.ConfigurationProperties;
-import org.identityconnectors.framework.api.ConnectorInfoManager;
 import org.identityconnectors.framework.api.ConnectorKey;
+import org.identityconnectors.framework.common.objects.AttributeInfo;
 import org.identityconnectors.framework.common.objects.AttributeUtil;
 import org.identityconnectors.framework.common.objects.ObjectClassInfo;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -149,9 +147,8 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
                     try {
                         result = binder.getConnInstanceTO(connInstance);
                     } catch (NotFoundException e) {
-                        LOG.
-                                error("Connector '{}#{}' not found", connInstance.getBundleName(), connInstance.
-                                        getVersion());
+                        LOG.error("Connector '{}#{}' not found",
+                                connInstance.getBundleName(), connInstance.getVersion());
                     }
 
                     return result;
@@ -181,29 +178,31 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
         }
 
         List<ConnBundleTO> connectorBundleTOs = new ArrayList<>();
-        for (Map.Entry<URI, ConnectorInfoManager> entry : connIdBundleManager.getConnInfoManagers().entrySet()) {
-            entry.getValue().getConnectorInfos().stream().map(bundle -> {
+        connIdBundleManager.getConnInfoManagers().forEach((uri, cim) -> {
+            connectorBundleTOs.addAll(cim.getConnectorInfos().stream().map(bundle -> {
                 ConnBundleTO connBundleTO = new ConnBundleTO();
                 connBundleTO.setDisplayName(bundle.getConnectorDisplayName());
-                connBundleTO.setLocation(entry.getKey().toString());
+
+                connBundleTO.setLocation(uri.toString());
+
                 ConnectorKey key = bundle.getConnectorKey();
                 connBundleTO.setBundleName(key.getBundleName());
                 connBundleTO.setConnectorName(key.getConnectorName());
                 connBundleTO.setVersion(key.getBundleVersion());
+
                 ConfigurationProperties properties = connIdBundleManager.getConfigurationProperties(bundle);
-                for (String propName : properties.getPropertyNames()) {
-                    connBundleTO.getProperties().add(binder.build(properties.getProperty(propName)));
-                }
+                connBundleTO.getProperties().addAll(properties.getPropertyNames().stream().
+                        map(propName -> binder.build(properties.getProperty(propName))).collect(Collectors.toList()));
+
                 return connBundleTO;
-            }).forEachOrdered(connBundleTO -> {
-                connectorBundleTOs.add(connBundleTO);
-            });
-        }
+            }).collect(Collectors.toList()));
+        });
 
         return connectorBundleTOs;
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_READ + "')")
+
     public List<ConnIdObjectClassTO> buildObjectClassInfo(
             final ConnInstanceTO connInstanceTO, final boolean includeSpecial) {
 
@@ -217,23 +216,19 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
                 connFactory.buildConnInstanceOverride(actual, connInstanceTO.getConf(), null)).
                 getObjectClassInfo();
 
-        List<ConnIdObjectClassTO> result = new ArrayList<>(objectClassInfo.size());
-        objectClassInfo.stream().map(info -> {
+        return objectClassInfo.stream().map(info -> {
             ConnIdObjectClassTO connIdObjectClassTO = new ConnIdObjectClassTO();
             connIdObjectClassTO.setType(info.getType());
             connIdObjectClassTO.setAuxiliary(info.isAuxiliary());
             connIdObjectClassTO.setContainer(info.isContainer());
-            info.getAttributeInfo().stream().
+
+            connIdObjectClassTO.getAttributes().addAll(info.getAttributeInfo().stream().
                     filter(attrInfo -> includeSpecial || !AttributeUtil.isSpecialName(attrInfo.getName())).
-                    forEachOrdered(attrInfo -> {
-                        connIdObjectClassTO.getAttributes().add(attrInfo.getName());
-                    });
-            return connIdObjectClassTO;
-        }).forEachOrdered((connIdObjectClassTO) -> {
-            result.add(connIdObjectClassTO);
-        });
+                    map(AttributeInfo::getName).
+                    collect(Collectors.toList()));
 
-        return result;
+            return connIdObjectClassTO;
+        }).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_READ + "')")

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/DomainLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/DomainLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/DomainLogic.java
index d9d29ba..9e3967b 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/DomainLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/DomainLogic.java
@@ -33,6 +33,7 @@ import org.apache.syncope.core.provisioning.api.data.DomainDataBinder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class DomainLogic extends AbstractTransactionalLogic<DomainTO> {
@@ -48,6 +49,7 @@ public class DomainLogic extends AbstractTransactionalLogic<DomainTO> {
 
     @PreAuthorize("hasRole('" + StandardEntitlement.DOMAIN_READ + "') and authentication.details.domain == "
             + "T(org.apache.syncope.common.lib.SyncopeConstants).MASTER_DOMAIN")
+    @Transactional(readOnly = true)
     public DomainTO read(final String key) {
         Domain domain = domainDAO.find(key);
         if (domain == null) {
@@ -60,8 +62,9 @@ public class DomainLogic extends AbstractTransactionalLogic<DomainTO> {
     }
 
     @PreAuthorize("isAuthenticated()")
+    @Transactional(readOnly = true)
     public List<DomainTO> list() {
-        return domainDAO.findAll().stream().map(domain -> binder.getDomainTO(domain)).collect(Collectors.toList());
+        return domainDAO.findAll().stream().map(binder::getDomainTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.DOMAIN_CREATE + "') and authentication.details.domain == "

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/DynRealmLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/DynRealmLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/DynRealmLogic.java
index de9e78a..487cc59 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/DynRealmLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/DynRealmLogic.java
@@ -31,6 +31,7 @@ import org.apache.syncope.core.provisioning.api.data.DynRealmDataBinder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class DynRealmLogic extends AbstractTransactionalLogic<DynRealmTO> {
@@ -42,6 +43,7 @@ public class DynRealmLogic extends AbstractTransactionalLogic<DynRealmTO> {
     private DynRealmDAO dynRealmDAO;
 
     @PreAuthorize("hasRole('" + StandardEntitlement.DYNREALM_READ + "')")
+    @Transactional(readOnly = true)
     public DynRealmTO read(final String key) {
         DynRealm dynRealm = dynRealmDAO.find(key);
         if (dynRealm == null) {
@@ -53,9 +55,9 @@ public class DynRealmLogic extends AbstractTransactionalLogic<DynRealmTO> {
         return binder.getDynRealmTO(dynRealm);
     }
 
+    @Transactional(readOnly = true)
     public List<DynRealmTO> list() {
-        return dynRealmDAO.findAll().stream().
-                map(dynRealm -> binder.getDynRealmTO(dynRealm)).collect(Collectors.toList());
+        return dynRealmDAO.findAll().stream().map(binder::getDynRealmTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.DYNREALM_CREATE + "')")

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/ImplementationLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ImplementationLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ImplementationLogic.java
index 83bc933..3079483 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ImplementationLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ImplementationLogic.java
@@ -43,6 +43,7 @@ import org.apache.syncope.core.provisioning.api.data.ImplementationDataBinder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class ImplementationLogic extends AbstractTransactionalLogic<ImplementationTO> {
@@ -75,12 +76,13 @@ public class ImplementationLogic extends AbstractTransactionalLogic<Implementati
     private NotificationDAO notificationDAO;
 
     @PreAuthorize("hasRole('" + StandardEntitlement.IMPLEMENTATION_LIST + "')")
+    @Transactional(readOnly = true)
     public List<ImplementationTO> list(final ImplementationType type) {
-        return implementationDAO.find(type).stream().
-                map(implementation -> binder.getImplementationTO(implementation)).collect(Collectors.toList());
+        return implementationDAO.find(type).stream().map(binder::getImplementationTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.IMPLEMENTATION_READ + "')")
+    @Transactional(readOnly = true)
     public ImplementationTO read(final ImplementationType type, final String key) {
         Implementation implementation = implementationDAO.find(key);
         if (implementation == null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/LoggerLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/LoggerLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/LoggerLogic.java
index 0867c62..c576774 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/LoggerLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/LoggerLogic.java
@@ -95,6 +95,7 @@ public class LoggerLogic extends AbstractTransactionalLogic<LoggerTO> {
 
     @PreAuthorize("hasRole('" + StandardEntitlement.LOG_LIST + "') and authentication.details.domain == "
             + "T(org.apache.syncope.common.lib.SyncopeConstants).MASTER_DOMAIN")
+    @Transactional(readOnly = true)
     public List<LogAppender> memoryAppenders() {
         return loggerLoader.getMemoryAppenders().keySet().stream().map(appender -> {
             LogAppender logAppender = new LogAppender();
@@ -105,6 +106,7 @@ public class LoggerLogic extends AbstractTransactionalLogic<LoggerTO> {
 
     @PreAuthorize("hasRole('" + StandardEntitlement.LOG_READ + "') and authentication.details.domain == "
             + "T(org.apache.syncope.common.lib.SyncopeConstants).MASTER_DOMAIN")
+    @Transactional(readOnly = true)
     public List<LogStatementTO> getLastLogStatements(final String memoryAppender) {
         MemoryAppender appender = loggerLoader.getMemoryAppenders().get(memoryAppender);
         if (appender == null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/MailTemplateLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/MailTemplateLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/MailTemplateLogic.java
index 3f2b7c8..d33d68a 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/MailTemplateLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/MailTemplateLogic.java
@@ -39,6 +39,7 @@ import org.apache.syncope.core.persistence.api.entity.Notification;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class MailTemplateLogic extends AbstractTransactionalLogic<MailTemplateTO> {
@@ -59,6 +60,7 @@ public class MailTemplateLogic extends AbstractTransactionalLogic<MailTemplateTO
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.MAIL_TEMPLATE_READ + "')")
+    @Transactional(readOnly = true)
     public MailTemplateTO read(final String key) {
         MailTemplate mailTemplate = mailTemplateDAO.find(key);
         if (mailTemplate == null) {
@@ -71,6 +73,7 @@ public class MailTemplateLogic extends AbstractTransactionalLogic<MailTemplateTO
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.MAIL_TEMPLATE_LIST + "')")
+    @Transactional(readOnly = true)
     public List<MailTemplateTO> list() {
         return mailTemplateDAO.findAll().stream().
                 map(template -> getMailTemplateTO(template.getKey())).collect(Collectors.toList());

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/NotificationLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/NotificationLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/NotificationLogic.java
index b594613..d9a662f 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/NotificationLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/NotificationLogic.java
@@ -38,6 +38,7 @@ import org.quartz.JobKey;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class NotificationLogic extends AbstractJobLogic<NotificationTO> {
@@ -49,6 +50,7 @@ public class NotificationLogic extends AbstractJobLogic<NotificationTO> {
     private NotificationDataBinder binder;
 
     @PreAuthorize("hasRole('" + StandardEntitlement.NOTIFICATION_READ + "')")
+    @Transactional(readOnly = true)
     public NotificationTO read(final String key) {
         Notification notification = notificationDAO.find(key);
         if (notification == null) {
@@ -61,9 +63,9 @@ public class NotificationLogic extends AbstractJobLogic<NotificationTO> {
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.NOTIFICATION_LIST + "')")
+    @Transactional(readOnly = true)
     public List<NotificationTO> list() {
-        return notificationDAO.findAll().stream().
-                map(notification -> binder.getNotificationTO(notification)).collect(Collectors.toList());
+        return notificationDAO.findAll().stream().map(binder::getNotificationTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.NOTIFICATION_CREATE + "')")

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/PolicyLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/PolicyLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/PolicyLogic.java
index 2506a90..29f3052 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/PolicyLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/PolicyLogic.java
@@ -36,6 +36,7 @@ import org.apache.syncope.core.provisioning.api.data.PolicyDataBinder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class PolicyLogic extends AbstractTransactionalLogic<PolicyTO> {
@@ -76,14 +77,16 @@ public class PolicyLogic extends AbstractTransactionalLogic<PolicyTO> {
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.POLICY_LIST + "')")
+    @Transactional(readOnly = true)
     public <T extends PolicyTO> List<T> list(final PolicyType type) {
         PolicyUtils policyUtils = policyUtilsFactory.getInstance(type);
 
         return policyDAO.find(policyUtils.policyClass()).stream().
-                <T>map(policy -> binder.getPolicyTO(policy)).collect(Collectors.toList());
+                <T>map(binder::getPolicyTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.POLICY_READ + "')")
+    @Transactional(readOnly = true)
     public <T extends PolicyTO> T read(final PolicyType type, final String key) {
         Policy policy = policyDAO.find(key);
         if (policy == null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
index 4c2a8cc..86a1847 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java
@@ -50,6 +50,7 @@ import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class RealmLogic extends AbstractTransactionalLogic<RealmTO> {
@@ -70,6 +71,7 @@ public class RealmLogic extends AbstractTransactionalLogic<RealmTO> {
     private PropagationTaskExecutor taskExecutor;
 
     @PreAuthorize("isAuthenticated()")
+    @Transactional(readOnly = true)
     public List<RealmTO> list(final String fullPath) {
         Realm realm = realmDAO.findByFullPath(fullPath);
         if (realm == null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/RelationshipTypeLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/RelationshipTypeLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/RelationshipTypeLogic.java
index 30ac9a2..b0c1ff5 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/RelationshipTypeLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/RelationshipTypeLogic.java
@@ -32,6 +32,7 @@ import org.apache.syncope.core.provisioning.api.data.RelationshipTypeDataBinder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class RelationshipTypeLogic extends AbstractTransactionalLogic<RelationshipTypeTO> {
@@ -43,6 +44,7 @@ public class RelationshipTypeLogic extends AbstractTransactionalLogic<Relationsh
     private RelationshipTypeDAO relationshipTypeDAO;
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RELATIONSHIPTYPE_READ + "')")
+    @Transactional(readOnly = true)
     public RelationshipTypeTO read(final String key) {
         RelationshipType relationshipType = relationshipTypeDAO.find(key);
         if (relationshipType == null) {
@@ -55,9 +57,9 @@ public class RelationshipTypeLogic extends AbstractTransactionalLogic<Relationsh
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RELATIONSHIPTYPE_LIST + "')")
+    @Transactional(readOnly = true)
     public List<RelationshipTypeTO> list() {
-        return relationshipTypeDAO.findAll().stream().
-                map(relationshipType -> binder.getRelationshipTypeTO(relationshipType)).collect(Collectors.toList());
+        return relationshipTypeDAO.findAll().stream().map(binder::getRelationshipTypeTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RELATIONSHIPTYPE_CREATE + "')")

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/RemediationLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/RemediationLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/RemediationLogic.java
new file mode 100644
index 0000000..1fb93e0
--- /dev/null
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/RemediationLogic.java
@@ -0,0 +1,210 @@
+/*
+ * 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.List;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.patch.AnyObjectPatch;
+import org.apache.syncope.common.lib.patch.AnyPatch;
+import org.apache.syncope.common.lib.patch.GroupPatch;
+import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.ProvisioningResult;
+import org.apache.syncope.common.lib.to.RemediationTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.RemediationDAO;
+import org.apache.syncope.core.persistence.api.entity.Remediation;
+import org.apache.syncope.core.provisioning.api.data.RemediationDataBinder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class RemediationLogic extends AbstractTransactionalLogic<RemediationTO> {
+
+    @Autowired
+    private UserLogic userLogic;
+
+    @Autowired
+    private GroupLogic groupLogic;
+
+    @Autowired
+    private AnyObjectLogic anyObjectLogic;
+
+    @Autowired
+    private RemediationDataBinder binder;
+
+    @Autowired
+    private RemediationDAO remediationDAO;
+
+    @PreAuthorize("hasRole('" + StandardEntitlement.REMEDIATION_LIST + "')")
+    @Transactional(readOnly = true)
+    public List<RemediationTO> list() {
+        return remediationDAO.findAll().stream().map(binder::getRemediationTO).collect(Collectors.toList());
+    }
+
+    @PreAuthorize("hasRole('" + StandardEntitlement.REMEDIATION_READ + "')")
+    @Transactional(readOnly = true)
+    public RemediationTO read(final String key) {
+        Remediation remediation = remediationDAO.find(key);
+        if (remediation == null) {
+            LOG.error("Could not find remediation '" + key + "'");
+
+            throw new NotFoundException(key);
+        }
+
+        return binder.getRemediationTO(remediation);
+    }
+
+    @PreAuthorize("hasRole('" + StandardEntitlement.REMEDIATION_DELETE + "')")
+    public void delete(final String key) {
+        Remediation remediation = remediationDAO.find(key);
+        if (remediation == null) {
+            LOG.error("Could not find remediation '" + key + "'");
+
+            throw new NotFoundException(key);
+        }
+
+        remediationDAO.delete(remediation);
+    }
+
+    @PreAuthorize("hasRole('" + StandardEntitlement.REMEDIATION_REMEDY + "')")
+    public ProvisioningResult<?> remedy(final String key, final AnyTO anyTO, final boolean nullPriorityAsync) {
+        Remediation remediation = remediationDAO.find(key);
+        if (remediation == null) {
+            LOG.error("Could not find remediation '" + key + "'");
+
+            throw new NotFoundException(key);
+        }
+
+        ProvisioningResult<?> result;
+        switch (remediation.getAnyTypeKind()) {
+            case USER:
+            default:
+                result = userLogic.create((UserTO) anyTO, true, nullPriorityAsync);
+                break;
+
+            case GROUP:
+                result = groupLogic.create((GroupTO) anyTO, nullPriorityAsync);
+                break;
+
+            case ANY_OBJECT:
+                result = anyObjectLogic.create((AnyObjectTO) anyTO, nullPriorityAsync);
+        }
+
+        remediationDAO.delete(remediation);
+
+        return result;
+    }
+
+    @PreAuthorize("hasRole('" + StandardEntitlement.REMEDIATION_REMEDY + "')")
+    public ProvisioningResult<?> remedy(final String key, final AnyPatch anyPatch, final boolean nullPriorityAsync) {
+        Remediation remediation = remediationDAO.find(key);
+        if (remediation == null) {
+            LOG.error("Could not find remediation '" + key + "'");
+
+            throw new NotFoundException(key);
+        }
+
+        ProvisioningResult<?> result;
+        switch (remediation.getAnyTypeKind()) {
+            case USER:
+            default:
+                result = userLogic.update((UserPatch) anyPatch, nullPriorityAsync);
+                break;
+
+            case GROUP:
+                result = groupLogic.update((GroupPatch) anyPatch, nullPriorityAsync);
+                break;
+
+            case ANY_OBJECT:
+                result = anyObjectLogic.update((AnyObjectPatch) anyPatch, nullPriorityAsync);
+        }
+
+        remediationDAO.delete(remediation);
+
+        return result;
+    }
+
+    @PreAuthorize("hasRole('" + StandardEntitlement.REMEDIATION_REMEDY + "')")
+    public ProvisioningResult<?> remedy(final String key, final String anyKey, final boolean nullPriorityAsync) {
+        Remediation remediation = remediationDAO.find(key);
+        if (remediation == null) {
+            LOG.error("Could not find remediation '" + key + "'");
+
+            throw new NotFoundException(key);
+        }
+
+        ProvisioningResult<?> result;
+        switch (remediation.getAnyTypeKind()) {
+            case USER:
+            default:
+                result = userLogic.delete(anyKey, nullPriorityAsync);
+                break;
+
+            case GROUP:
+                result = groupLogic.delete(anyKey, nullPriorityAsync);
+                break;
+
+            case ANY_OBJECT:
+                result = anyObjectLogic.delete(anyKey, nullPriorityAsync);
+        }
+
+        remediationDAO.delete(remediation);
+
+        return result;
+    }
+
+    @Override
+    protected RemediationTO resolveReference(final Method method, final Object... args)
+            throws UnresolvedReferenceException {
+
+        String key = null;
+
+        if (ArrayUtils.isNotEmpty(args)) {
+            for (int i = 0; key == null && i < args.length; i++) {
+                if (args[i] instanceof String) {
+                    key = (String) args[i];
+                } else if (args[i] instanceof RemediationTO) {
+                    key = ((RemediationTO) args[i]).getKey();
+                }
+            }
+        }
+
+        if (StringUtils.isNotBlank(key)) {
+            try {
+                return binder.getRemediationTO(remediationDAO.find(key));
+            } catch (Throwable ignore) {
+                LOG.debug("Unresolved reference", ignore);
+                throw new UnresolvedReferenceException(ignore);
+            }
+        }
+
+        throw new UnresolvedReferenceException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
index 6a5a442..780e8ac 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ReportLogic.java
@@ -68,6 +68,7 @@ import org.quartz.SchedulerException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class ReportLogic extends AbstractExecutableLogic<ReportTO> {
@@ -136,11 +137,13 @@ public class ReportLogic extends AbstractExecutableLogic<ReportTO> {
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.REPORT_LIST + "')")
+    @Transactional(readOnly = true)
     public List<ReportTO> list() {
-        return reportDAO.findAll().stream().map(report -> binder.getReportTO(report)).collect(Collectors.toList());
+        return reportDAO.findAll().stream().map(binder::getReportTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.REPORT_READ + "')")
+    @Transactional(readOnly = true)
     public ReportTO read(final String key) {
         Report report = reportDAO.find(key);
         if (report == null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/ReportTemplateLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ReportTemplateLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ReportTemplateLogic.java
index d59831c..5dc61c1 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ReportTemplateLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ReportTemplateLogic.java
@@ -39,6 +39,7 @@ import org.apache.syncope.core.persistence.api.entity.Report;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class ReportTemplateLogic extends AbstractTransactionalLogic<ReportTemplateTO> {
@@ -59,6 +60,7 @@ public class ReportTemplateLogic extends AbstractTransactionalLogic<ReportTempla
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.REPORT_TEMPLATE_READ + "')")
+    @Transactional(readOnly = true)
     public ReportTemplateTO read(final String key) {
         ReportTemplate reportTemplate = reportTemplateDAO.find(key);
         if (reportTemplate == null) {
@@ -71,6 +73,7 @@ public class ReportTemplateLogic extends AbstractTransactionalLogic<ReportTempla
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.REPORT_TEMPLATE_LIST + "')")
+    @Transactional(readOnly = true)
     public List<ReportTemplateTO> list() {
         return reportTemplateDAO.findAll().stream().
                 map(template -> getReportTemplateTO(template.getKey())).collect(Collectors.toList());

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceHistoryLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceHistoryLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceHistoryLogic.java
index d027e97..42126fb 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceHistoryLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceHistoryLogic.java
@@ -32,6 +32,7 @@ import org.apache.syncope.core.provisioning.api.data.ResourceDataBinder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 @Component
 public class ResourceHistoryLogic extends AbstractTransactionalLogic<ResourceHistoryConfTO> {
@@ -45,17 +46,8 @@ public class ResourceHistoryLogic extends AbstractTransactionalLogic<ResourceHis
     @Autowired
     private ResourceDataBinder binder;
 
-    private ResourceHistoryConfTO getResourceHistoryConfTO(final ExternalResourceHistoryConf history) {
-        ResourceHistoryConfTO historyTO = new ResourceHistoryConfTO();
-        historyTO.setKey(history.getKey());
-        historyTO.setCreator(history.getCreator());
-        historyTO.setCreation(history.getCreation());
-        historyTO.setResourceTO(history.getConf());
-
-        return historyTO;
-    }
-
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_HISTORY_LIST + "')")
+    @Transactional(readOnly = true)
     public List<ResourceHistoryConfTO> list(final String key) {
         ExternalResource resource = resourceDAO.find(key);
         if (resource == null) {
@@ -63,7 +55,7 @@ public class ResourceHistoryLogic extends AbstractTransactionalLogic<ResourceHis
         }
 
         return resourceHistoryConfDAO.findByEntity(resource).stream().
-                map(historyConf -> getResourceHistoryConfTO(historyConf)).collect(Collectors.toList());
+                map(binder::getResourceHistoryConfTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_HISTORY_RESTORE + "')")
@@ -93,7 +85,7 @@ public class ResourceHistoryLogic extends AbstractTransactionalLogic<ResourceHis
         if (!"list".equals(method.getName())) {
             try {
                 String key = (String) args[0];
-                return getResourceHistoryConfTO(resourceHistoryConfDAO.find(key));
+                return binder.getResourceHistoryConfTO(resourceHistoryConfDAO.find(key));
             } catch (Throwable ignore) {
                 LOG.debug("Unresolved reference", ignore);
                 throw new UnresolvedReferenceException(ignore);

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index 1901393..e90b245 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -274,8 +274,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_LIST + "')")
     @Transactional(readOnly = true)
     public List<ResourceTO> list() {
-        return resourceDAO.findAll().stream().
-                map(resource -> binder.getResourceTO(resource)).collect(Collectors.toList());
+        return resourceDAO.findAll().stream().map(binder::getResourceTO).collect(Collectors.toList());
     }
 
     private Triple<ExternalResource, AnyType, Provision> connObjectInit(

http://git-wip-us.apache.org/repos/asf/syncope/blob/51b314fe/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
index e8b9f8a..a04e518 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
@@ -59,7 +59,7 @@ public class RoleLogic extends AbstractTransactionalLogic<RoleTO> {
     @PreAuthorize("hasRole('" + StandardEntitlement.ROLE_LIST + "')")
     @Transactional(readOnly = true)
     public List<RoleTO> list() {
-        return roleDAO.findAll().stream().map(role -> binder.getRoleTO(role)).collect(Collectors.toList());
+        return roleDAO.findAll().stream().map(binder::getRoleTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.ROLE_CREATE + "')")


Mime
View raw message