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 2022/09/01 12:04:10 UTC
[syncope] branch master updated: [SYNCOPE-1694] Refactor ImplementationManager to allow either per-class and per-instance caches (#372)
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new 5119be8c25 [SYNCOPE-1694] Refactor ImplementationManager to allow either per-class and per-instance caches (#372)
5119be8c25 is described below
commit 5119be8c2506d5aaa0965dd085a01756fbd3c91a
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Thu Sep 1 14:04:04 2022 +0200
[SYNCOPE-1694] Refactor ImplementationManager to allow either per-class and per-instance caches (#372)
---
.../common/lib/types/ConnectorCapability.java | 1 +
.../syncope/core/logic/AbstractAnyLogic.java | 13 +-
.../init/ClassPathScanImplementationLookup.java | 4 +-
...idator.java => PlainAttrValidationManager.java} | 6 +-
...Validator.java => PlainAttrValueValidator.java} | 6 +-
.../core/persistence/api/entity/AnyUtils.java | 3 +-
.../core/persistence/api/entity/PlainAttr.java | 6 +-
.../jpa/MyJPAJSONPersistenceContext.java | 7 +-
.../jpa/PGJPAJSONPersistenceContext.java | 11 +-
.../persistence/jpa/dao/MyJPAJSONAnySearchDAO.java | 17 +-
.../persistence/jpa/dao/PGJPAJSONAnySearchDAO.java | 19 +-
.../entity/JPAJSONAttributableValidator.java | 2 +-
.../src/test/resources/domains/MasterContent.xml | 4 +-
.../core/persistence/jpa/PersistenceContext.java | 26 ++-
.../attrvalue/validation/AbstractValidator.java | 17 +-
.../attrvalue/validation/AlwaysTrueValidator.java | 3 +-
.../jpa/attrvalue/validation/BasicValidator.java | 5 +-
.../jpa/attrvalue/validation/BinaryValidator.java | 3 +-
.../DefaultPlainAttrValidationManager.java | 60 +++++
.../validation/EmailAddressValidator.java | 3 +-
.../jpa/attrvalue/validation/URLValidator.java | 3 +-
.../persistence/jpa/dao/AbstractAnySearchDAO.java | 12 +-
.../core/persistence/jpa/dao/JPAAnyMatchDAO.java | 22 +-
.../core/persistence/jpa/dao/JPAAnySearchDAO.java | 17 +-
.../core/persistence/jpa/dao/JPAUserDAO.java | 71 ++++--
.../persistence/jpa/entity/AbstractPlainAttr.java | 9 +-
.../core/persistence/jpa/entity/JPAAnyUtils.java | 10 +-
.../persistence/jpa/entity/JPAPlainSchema.java | 28 ---
...trValidator.java => JPAPlainAttrValidator.java} | 2 +-
.../jpa/validation/entity/PlainAttrCheck.java | 2 +-
.../core/persistence/jpa/inner/PlainAttrTest.java | 24 +-
.../core/persistence/jpa/outer/AnySearchTest.java | 8 +-
.../core/persistence/jpa/outer/GroupTest.java | 12 +-
.../core/persistence/jpa/outer/RoleTest.java | 6 +-
.../core/persistence/jpa/outer/UserTest.java | 14 +-
.../src/test/resources/domains/MasterContent.xml | 4 +-
.../provisioning/java/ConnectorFacadeProxy.java | 2 +-
.../provisioning/java/ProvisioningContext.java | 19 +-
.../java/data/AbstractAnyDataBinder.java | 9 +-
.../java/data/AnyObjectDataBinderImpl.java | 7 +-
.../java/data/GroupDataBinderImpl.java | 7 +-
.../java/data/ImplementationDataBinderImpl.java | 4 +-
.../java/data/ResourceDataBinderImpl.java | 10 +-
.../provisioning/java/data/UserDataBinderImpl.java | 5 +-
.../notification/DefaultNotificationManager.java | 9 +-
.../AbstractPropagationTaskExecutor.java | 20 +-
.../java/propagation/AzurePropagationActions.java | 3 +
.../propagation/DBPasswordPropagationActions.java | 3 +
.../propagation/DefaultPropagationManager.java | 3 -
.../propagation/GoogleAppsPropagationActions.java | 3 +
.../LDAPMembershipPropagationActions.java | 3 +
.../LDAPPasswordPropagationActions.java | 3 +
.../PriorityPropagationTaskExecutor.java | 5 +-
.../pushpull/AbstractProvisioningJobDelegate.java | 23 ++
.../provisioning/java/pushpull/InboundMatcher.java | 54 +++--
.../java/pushpull/OutboundMatcher.java | 46 ++--
.../java/pushpull/PullJobDelegate.java | 71 +++---
.../java/pushpull/PushJobDelegate.java | 45 ++--
.../java/pushpull/SinglePullJobDelegate.java | 29 +--
.../java/pushpull/SinglePushJobDelegate.java | 37 +--
.../pushpull/stream/StreamPullJobDelegate.java | 27 +--
.../pushpull/stream/StreamPushJobDelegate.java | 25 +-
.../core/provisioning/java/utils/MappingUtils.java | 9 +-
.../java/DefaultMappingManagerTest.java | 6 +-
.../syncope/core/spring/ImplementationManager.java | 250 --------------------
.../implementation/ImplementationManager.java | 252 +++++++++++++++++++++
.../core/spring/implementation/InstanceScope.java | 23 +-
.../implementation/SyncopeImplementation.java} | 15 +-
.../spring/security/DefaultPasswordGenerator.java | 38 +++-
.../core/spring/ImplementationManagerTest.java | 10 +-
.../jpa/ElasticsearchPersistenceContext.java | 3 +
.../jpa/dao/ElasticsearchAnySearchDAO.java | 14 +-
.../core/reference/DateToDateItemTransformer.java | 3 +
.../core/reference/DateToLongItemTransformer.java | 3 +
74 files changed, 919 insertions(+), 639 deletions(-)
diff --git a/common/idm/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java b/common/idm/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java
index 1abf35f88a..70c9f4170a 100644
--- a/common/idm/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java
+++ b/common/idm/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java
@@ -26,6 +26,7 @@ public enum ConnectorCapability {
AUTHENTICATE,
CREATE,
UPDATE,
+ UPDATE_DELTA,
DELETE,
SEARCH,
SYNC;
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
index c7a82a623b..1a21f400f6 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
@@ -20,6 +20,8 @@ package org.apache.syncope.core.logic;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.request.AnyCR;
@@ -52,6 +54,8 @@ public abstract class AbstractAnyLogic<TO extends AnyTO, C extends AnyCR, U exte
protected final TemplateUtils templateUtils;
+ protected final Map<String, LogicActions> perContextActions = new ConcurrentHashMap<>();
+
public AbstractAnyLogic(
final RealmDAO realmDAO,
final AnyTypeDAO anyTypeDAO,
@@ -63,17 +67,20 @@ public abstract class AbstractAnyLogic<TO extends AnyTO, C extends AnyCR, U exte
}
protected List<LogicActions> getActions(final Realm realm) {
- List<LogicActions> actions = new ArrayList<>();
+ List<LogicActions> result = new ArrayList<>();
realm.getActions().forEach(impl -> {
try {
- actions.add(ImplementationManager.build(impl));
+ result.add(ImplementationManager.build(
+ impl,
+ () -> perContextActions.get(impl.getKey()),
+ instance -> perContextActions.put(impl.getKey(), instance)));
} catch (Exception e) {
LOG.warn("While building {}", impl, e);
}
});
- return actions;
+ return result;
}
@SuppressWarnings("unchecked")
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
index a673daea32..a9e3194667 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
@@ -36,7 +36,7 @@ import org.apache.syncope.common.lib.types.ImplementationTypesHolder;
import org.apache.syncope.core.logic.audit.AuditAppender;
import org.apache.syncope.core.logic.audit.JdbcAuditAppender;
import org.apache.syncope.core.persistence.api.ImplementationLookup;
-import org.apache.syncope.core.persistence.api.attrvalue.validation.Validator;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValueValidator;
import org.apache.syncope.core.persistence.api.dao.AccountRule;
import org.apache.syncope.core.persistence.api.dao.AccountRuleConfClass;
import org.apache.syncope.core.persistence.api.dao.PasswordRule;
@@ -225,7 +225,7 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
classNames.get(IdMImplementationType.PUSH_ACTIONS).add(bd.getBeanClassName());
}
- if (Validator.class.isAssignableFrom(clazz) && !isAbstractClazz) {
+ if (PlainAttrValueValidator.class.isAssignableFrom(clazz) && !isAbstractClazz) {
classNames.get(IdRepoImplementationType.VALIDATOR).add(bd.getBeanClassName());
}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/Validator.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/PlainAttrValidationManager.java
similarity index 88%
copy from core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/Validator.java
copy to core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/PlainAttrValidationManager.java
index 5b49b4ccf8..f686162dae 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/Validator.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/PlainAttrValidationManager.java
@@ -21,9 +21,7 @@ package org.apache.syncope.core.persistence.api.attrvalue.validation;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
-public interface Validator {
+public interface PlainAttrValidationManager {
- void setSchema(PlainSchema schema);
-
- void validate(String value, PlainAttrValue attrValue);
+ void validate(PlainSchema schema, String value, PlainAttrValue attrValue);
}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/Validator.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/PlainAttrValueValidator.java
similarity index 88%
rename from core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/Validator.java
rename to core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/PlainAttrValueValidator.java
index 5b49b4ccf8..44d1f21161 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/Validator.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/attrvalue/validation/PlainAttrValueValidator.java
@@ -21,9 +21,7 @@ package org.apache.syncope.core.persistence.api.attrvalue.validation;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
-public interface Validator {
+public interface PlainAttrValueValidator {
- void setSchema(PlainSchema schema);
-
- void validate(String value, PlainAttrValue attrValue);
+ void validate(PlainSchema schema, String value, PlainAttrValue attrValue);
}
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 4c65c764f5..0ceb427afe 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
@@ -24,6 +24,7 @@ import org.apache.syncope.common.lib.request.AnyCR;
import org.apache.syncope.common.lib.request.AnyUR;
import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyDAO;
public interface AnyUtils {
@@ -58,5 +59,5 @@ public interface AnyUtils {
Set<ExternalResource> getAllResources(Any<?> any);
- void addAttr(String key, PlainSchema schema, String value);
+ void addAttr(PlainAttrValidationManager validator, String key, PlainSchema schema, String value);
}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
index 2e44dcea67..15376c3016 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/PlainAttr.java
@@ -19,6 +19,7 @@
package org.apache.syncope.core.persistence.api.entity;
import java.util.List;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
public interface PlainAttr<A extends Any<?>> extends Entity {
@@ -30,9 +31,9 @@ public interface PlainAttr<A extends Any<?>> extends Entity {
void setSchema(PlainSchema schema);
- void add(String value, AnyUtils anyUtils);
+ void add(PlainAttrValidationManager validator, String value, AnyUtils anyUtils);
- void add(String value, PlainAttrValue attrValue);
+ void add(PlainAttrValidationManager validator, String value, PlainAttrValue attrValue);
PlainAttrUniqueValue getUniqueValue();
@@ -41,5 +42,4 @@ public interface PlainAttr<A extends Any<?>> extends Entity {
List<? extends PlainAttrValue> getValues();
List<String> getValuesAsStrings();
-
}
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java
index ab01aac0f2..b638bb1051 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.core.persistence.jpa;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
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.AuditConfDAO;
@@ -66,7 +67,8 @@ public class MyJPAJSONPersistenceContext extends JPAJSONPersistenceContext {
final @Lazy AnyObjectDAO anyObjectDAO,
final @Lazy PlainSchemaDAO schemaDAO,
final @Lazy EntityFactory entityFactory,
- final AnyUtilsFactory anyUtilsFactory) {
+ final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator) {
return new MyJPAJSONAnySearchDAO(
realmDAO,
@@ -76,7 +78,8 @@ public class MyJPAJSONPersistenceContext extends JPAJSONPersistenceContext {
anyObjectDAO,
schemaDAO,
entityFactory,
- anyUtilsFactory);
+ anyUtilsFactory,
+ validator);
}
@ConditionalOnMissingBean(name = "myJPAJSONAuditConfDAO")
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java
index 88e294914f..551b2c859d 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.core.persistence.jpa;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
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.AuditConfDAO;
@@ -64,9 +65,10 @@ public class PGJPAJSONPersistenceContext extends JPAJSONPersistenceContext {
final @Lazy UserDAO userDAO,
final @Lazy GroupDAO groupDAO,
final @Lazy AnyObjectDAO anyObjectDAO,
- final @Lazy PlainSchemaDAO plainSchemaDAO,
+ final @Lazy PlainSchemaDAO schemaDAO,
final @Lazy EntityFactory entityFactory,
- final AnyUtilsFactory anyUtilsFactory) {
+ final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator) {
return new PGJPAJSONAnySearchDAO(
realmDAO,
@@ -74,9 +76,10 @@ public class PGJPAJSONPersistenceContext extends JPAJSONPersistenceContext {
userDAO,
groupDAO,
anyObjectDAO,
- plainSchemaDAO,
+ schemaDAO,
entityFactory,
- anyUtilsFactory);
+ anyUtilsFactory,
+ validator);
}
@ConditionalOnMissingBean(name = "pgJPAJSONAuditConfDAO")
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
index 9d29051adf..a76fe02804 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
@@ -25,6 +25,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
@@ -54,9 +55,19 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO {
final AnyObjectDAO anyObjectDAO,
final PlainSchemaDAO schemaDAO,
final EntityFactory entityFactory,
- final AnyUtilsFactory anyUtilsFactory) {
-
- super(realmDAO, dynRealmDAO, userDAO, groupDAO, anyObjectDAO, schemaDAO, entityFactory, anyUtilsFactory);
+ final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator) {
+
+ super(
+ realmDAO,
+ dynRealmDAO,
+ userDAO,
+ groupDAO,
+ anyObjectDAO,
+ schemaDAO,
+ entityFactory,
+ anyUtilsFactory,
+ validator);
}
@Override
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
index 4c73c531a3..c9a209d822 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
@@ -33,6 +33,7 @@ import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.common.rest.api.service.JAXRSService;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
@@ -88,11 +89,21 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
final UserDAO userDAO,
final GroupDAO groupDAO,
final AnyObjectDAO anyObjectDAO,
- final PlainSchemaDAO plainSchemaDAO,
+ final PlainSchemaDAO schemaDAO,
final EntityFactory entityFactory,
- final AnyUtilsFactory anyUtilsFactory) {
-
- super(realmDAO, dynRealmDAO, userDAO, groupDAO, anyObjectDAO, plainSchemaDAO, entityFactory, anyUtilsFactory);
+ final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator) {
+
+ super(
+ realmDAO,
+ dynRealmDAO,
+ userDAO,
+ groupDAO,
+ anyObjectDAO,
+ schemaDAO,
+ entityFactory,
+ anyUtilsFactory,
+ validator);
}
@Override
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/JPAJSONAttributableValidator.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/JPAJSONAttributableValidator.java
index aa72fd46ce..0d93175844 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/JPAJSONAttributableValidator.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/JPAJSONAttributableValidator.java
@@ -29,7 +29,7 @@ public class JPAJSONAttributableValidator extends AbstractValidator<JPAJSONAttri
public boolean isValid(final JSONAttributable<?> entity, final ConstraintValidatorContext context) {
context.disableDefaultConstraintViolation();
- PlainAttrValidator attrValidator = new PlainAttrValidator();
+ JPAPlainAttrValidator attrValidator = new JPAPlainAttrValidator();
PlainAttrValueValidator attrValueValidator = new PlainAttrValueValidator();
AtomicReference<Boolean> isValid = new AtomicReference<>(Boolean.TRUE);
diff --git a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
index c3799e7347..b959f52e72 100644
--- a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
@@ -545,7 +545,7 @@ under the License.
connectorName="net.tirasa.connid.bundles.ldap.LdapConnector"
version="${connid.ldap.version}"
jsonConf='[{"schema":{"name":"host","type":"java.lang.String","required":true,"order":1,"confidential":false,"defaultValues":[]},"values":["localhost"],"overridable":false},{"schema":{"name":"port","type":"int","required":false,"order":2,"confidential":false,"defaultValues":[389]},"values":[1389],"overridable":false},{"schema":{"name":"ssl","type":"boolean","required":false,"order":3,"confidential":false,"defaultValues":[false]},"values":["false"],"overridable":false},{"s [...]
- capabilities='["CREATE","UPDATE","DELETE","SEARCH"]'/>
+ capabilities='["CREATE","UPDATE","UPDATE_DELTA","DELETE","SEARCH"]'/>
<ConnInstance id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" displayName="H2-test2"
adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
@@ -570,7 +570,7 @@ under the License.
connectorName="net.tirasa.connid.bundles.db.scriptedsql.ScriptedSQLConnector"
displayName="Scripted SQL" version="${connid.database.version}"
jsonConf='[{"schema":{"name":"updateScriptFileName","displayName":"updateScriptFileName","helpMessage":"updateScriptFileName","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":[]},"overridable":false,"values":["${conf.directory}/scriptedsql/UpdateScript.groovy"]},{"schem [...]
- capabilities='["CREATE","UPDATE","DELETE","SEARCH","SYNC"]'/>
+ capabilities='["CREATE","UPDATE","UPDATE_DELTA","DELETE","SEARCH","SYNC"]'/>
<ConnInstance id="44c02549-19c3-483c-8025-4919c3283c37" bundlename="net.tirasa.connid.bundles.rest"
adminRealm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
index b2e7b2cc5b..cf95524230 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
@@ -26,6 +26,7 @@ import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
import org.apache.syncope.common.keymaster.client.api.DomainOps;
import org.apache.syncope.core.persistence.api.DomainHolder;
import org.apache.syncope.core.persistence.api.DomainRegistry;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AccessTokenDAO;
import org.apache.syncope.core.persistence.api.dao.AnyMatchDAO;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
@@ -79,6 +80,7 @@ import org.apache.syncope.core.persistence.api.entity.am.ClientAppUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.policy.PolicyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.task.TaskUtilsFactory;
import org.apache.syncope.core.persistence.api.search.SearchCondVisitor;
+import org.apache.syncope.core.persistence.jpa.attrvalue.validation.DefaultPlainAttrValidationManager;
import org.apache.syncope.core.persistence.jpa.content.KeymasterConfParamLoader;
import org.apache.syncope.core.persistence.jpa.content.XMLContentExporter;
import org.apache.syncope.core.persistence.jpa.content.XMLContentLoader;
@@ -174,6 +176,12 @@ public class PersistenceContext {
return new LocalValidatorFactoryBean();
}
+ @ConditionalOnMissingBean
+ @Bean
+ public PlainAttrValidationManager plainAttrValidationManager() {
+ return new DefaultPlainAttrValidationManager();
+ }
+
@ConditionalOnMissingBean
@Bean
public CommonEntityManagerFactoryConf commonEMFConf(final PersistenceProperties persistenceProperties) {
@@ -321,9 +329,17 @@ public class PersistenceContext {
final @Lazy AnyObjectDAO anyObjectDAO,
final RealmDAO realmDAO,
final PlainSchemaDAO plainSchemaDAO,
- final AnyUtilsFactory anyUtilsFactory) {
+ final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator) {
- return new JPAAnyMatchDAO(userDAO, groupDAO, anyObjectDAO, realmDAO, plainSchemaDAO, anyUtilsFactory);
+ return new JPAAnyMatchDAO(
+ userDAO,
+ groupDAO,
+ anyObjectDAO,
+ realmDAO,
+ plainSchemaDAO,
+ anyUtilsFactory,
+ validator);
}
@ConditionalOnMissingBean
@@ -355,7 +371,8 @@ public class PersistenceContext {
final @Lazy AnyObjectDAO anyObjectDAO,
final PlainSchemaDAO schemaDAO,
final EntityFactory entityFactory,
- final AnyUtilsFactory anyUtilsFactory) {
+ final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator) {
return new JPAAnySearchDAO(
realmDAO,
@@ -365,7 +382,8 @@ public class PersistenceContext {
anyObjectDAO,
schemaDAO,
entityFactory,
- anyUtilsFactory);
+ anyUtilsFactory,
+ validator);
}
@ConditionalOnMissingBean
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AbstractValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AbstractValidator.java
index 8c149db99a..4bcecbb353 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AbstractValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AbstractValidator.java
@@ -19,30 +19,23 @@
package org.apache.syncope.core.persistence.jpa.attrvalue.validation;
import java.io.Serializable;
-import org.apache.syncope.core.persistence.api.attrvalue.validation.Validator;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValueValidator;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public abstract class AbstractValidator implements Validator, Serializable {
+public abstract class AbstractValidator implements PlainAttrValueValidator, Serializable {
private static final long serialVersionUID = -5439345166669502493L;
protected static final Logger LOG = LoggerFactory.getLogger(AbstractValidator.class);
- protected PlainSchema schema;
-
- @Override
- public void setSchema(final PlainSchema schema) {
- this.schema = schema;
- }
-
@Override
- public void validate(final String value, final PlainAttrValue attrValue) {
+ public void validate(final PlainSchema schema, final String value, final PlainAttrValue attrValue) {
attrValue.parseValue(schema, value);
- doValidate(attrValue);
+ doValidate(schema, attrValue);
}
- protected abstract void doValidate(PlainAttrValue attrValue);
+ protected abstract void doValidate(PlainSchema schema, PlainAttrValue attrValue);
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AlwaysTrueValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AlwaysTrueValidator.java
index 65d63edc4f..887eefc3df 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AlwaysTrueValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AlwaysTrueValidator.java
@@ -20,13 +20,14 @@ package org.apache.syncope.core.persistence.jpa.attrvalue.validation;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
public class AlwaysTrueValidator extends AbstractValidator {
private static final long serialVersionUID = 872107345555773183L;
@Override
- protected void doValidate(final PlainAttrValue attrValue) {
+ protected void doValidate(final PlainSchema schema, final PlainAttrValue attrValue) {
Boolean value = attrValue.getValue();
if (!value) {
throw new InvalidPlainAttrValueException("This attribute must be set to \"true\"");
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BasicValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BasicValidator.java
index 2e62e16b58..13840dabbe 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BasicValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BasicValidator.java
@@ -22,13 +22,14 @@ import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
public class BasicValidator extends AbstractValidator {
private static final long serialVersionUID = -2606728447694223607L;
@Override
- protected void doValidate(final PlainAttrValue attrValue) {
+ protected void doValidate(final PlainSchema schema, final PlainAttrValue attrValue) {
if (AttrSchemaType.Enum == schema.getType()) {
final String[] enumeration = schema.getEnumerationValues().split(SyncopeConstants.ENUM_VALUES_SEPARATOR);
final String value = attrValue.getStringValue();
@@ -42,7 +43,7 @@ public class BasicValidator extends AbstractValidator {
if (!found) {
throw new InvalidPlainAttrValueException(
- '\'' + value + "' is not one of: " + schema.getEnumerationValues());
+ '\'' + value + "' is not one of: " + schema.getEnumerationValues());
}
}
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BinaryValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BinaryValidator.java
index 0df8bb2bf3..bc7d2fdc00 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BinaryValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BinaryValidator.java
@@ -23,6 +23,7 @@ import java.io.IOException;
import javax.ws.rs.core.MediaType;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.tika.Tika;
public class BinaryValidator extends AbstractValidator {
@@ -38,7 +39,7 @@ public class BinaryValidator extends AbstractValidator {
}
@Override
- protected void doValidate(final PlainAttrValue attrValue) {
+ protected void doValidate(final PlainSchema schema, final PlainAttrValue attrValue) {
// check Binary schemas MIME Type mismatches
if (attrValue.getBinaryValue() != null) {
byte[] binaryValue = attrValue.getBinaryValue();
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/DefaultPlainAttrValidationManager.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/DefaultPlainAttrValidationManager.java
new file mode 100644
index 0000000000..7cc027488e
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/DefaultPlainAttrValidationManager.java
@@ -0,0 +1,60 @@
+/*
+ * 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.persistence.jpa.attrvalue.validation;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValueValidator;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.spring.ImplementationManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultPlainAttrValidationManager implements PlainAttrValidationManager {
+
+ protected static final Logger LOG = LoggerFactory.getLogger(DefaultPlainAttrValidationManager.class);
+
+ protected static final PlainAttrValueValidator BASIC_VALIDATOR = new BasicValidator();
+
+ protected final Map<String, PlainAttrValueValidator> perContextValidators = new ConcurrentHashMap<>();
+
+ @Override
+ public void validate(final PlainSchema schema, final String value, final PlainAttrValue attrValue) {
+ PlainAttrValueValidator validator = null;
+
+ if (schema.getValidator() != null) {
+ try {
+ validator = ImplementationManager.build(
+ schema.getValidator(),
+ () -> perContextValidators.get(schema.getValidator().getKey()),
+ instance -> perContextValidators.put(schema.getValidator().getKey(), instance));
+ } catch (Exception e) {
+ LOG.error("While building {}", schema.getValidator(), e);
+ }
+ }
+
+ if (validator == null) {
+ validator = BASIC_VALIDATOR;
+ }
+
+ validator.validate(schema, value, attrValue);
+ }
+}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/EmailAddressValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/EmailAddressValidator.java
index ebc9e9d044..3fa84390fa 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/EmailAddressValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/EmailAddressValidator.java
@@ -22,13 +22,14 @@ import java.util.regex.Matcher;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
import org.apache.syncope.core.persistence.api.entity.Entity;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
public class EmailAddressValidator extends AbstractValidator {
private static final long serialVersionUID = 792457177290331518L;
@Override
- protected void doValidate(final PlainAttrValue attrValue) {
+ protected void doValidate(final PlainSchema schema, final PlainAttrValue attrValue) {
Matcher matcher = Entity.EMAIL_PATTERN.matcher(attrValue.<CharSequence>getValue());
if (!matcher.matches()) {
throw new InvalidPlainAttrValueException("\"" + attrValue.getValue() + "\" is not a valid email address");
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/URLValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/URLValidator.java
index 5646b0b1e2..acb8f6b9b0 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/URLValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/URLValidator.java
@@ -22,13 +22,14 @@ import java.net.MalformedURLException;
import java.net.URL;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
public class URLValidator extends AbstractValidator {
private static final long serialVersionUID = 792457177290331518L;
@Override
- protected void doValidate(final PlainAttrValue attrValue) {
+ protected void doValidate(final PlainSchema schema, final PlainAttrValue attrValue) {
try {
new URL(attrValue.getStringValue());
} catch (MalformedURLException e) {
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
index 53863ab241..0443b45761 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
@@ -35,6 +35,7 @@ import org.apache.commons.lang3.tuple.Triple;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
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.DynRealmDAO;
@@ -60,7 +61,6 @@ import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
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.jpa.entity.JPAPlainSchema;
import org.springframework.util.CollectionUtils;
public abstract class AbstractAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO {
@@ -126,6 +126,8 @@ public abstract class AbstractAnySearchDAO extends AbstractDAO<Any<?>> implement
protected final AnyUtilsFactory anyUtilsFactory;
+ protected final PlainAttrValidationManager validator;
+
public AbstractAnySearchDAO(
final RealmDAO realmDAO,
final DynRealmDAO dynRealmDAO,
@@ -134,7 +136,8 @@ public abstract class AbstractAnySearchDAO extends AbstractDAO<Any<?>> implement
final AnyObjectDAO anyObjectDAO,
final PlainSchemaDAO plainSchemaDAO,
final EntityFactory entityFactory,
- final AnyUtilsFactory anyUtilsFactory) {
+ final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator) {
this.realmDAO = realmDAO;
this.dynRealmDAO = dynRealmDAO;
@@ -144,6 +147,7 @@ public abstract class AbstractAnySearchDAO extends AbstractDAO<Any<?>> implement
this.plainSchemaDAO = plainSchemaDAO;
this.entityFactory = entityFactory;
this.anyUtilsFactory = anyUtilsFactory;
+ this.validator = validator;
}
protected abstract int doCount(
@@ -210,7 +214,7 @@ public abstract class AbstractAnySearchDAO extends AbstractDAO<Any<?>> implement
&& cond.getType() != AttrCond.Type.ISNULL
&& cond.getType() != AttrCond.Type.ISNOTNULL) {
- ((JPAPlainSchema) schema).validator().validate(cond.getExpression(), attrValue);
+ validator.validate(schema, cond.getExpression(), attrValue);
}
} catch (ValidationException e) {
throw new IllegalArgumentException("Could not validate expression " + cond.getExpression());
@@ -272,7 +276,7 @@ public abstract class AbstractAnySearchDAO extends AbstractDAO<Any<?>> implement
&& computed.getType() != AttrCond.Type.ISNOTNULL) {
try {
- ((JPAPlainSchema) schema).validator().validate(computed.getExpression(), attrValue);
+ validator.validate(schema, computed.getExpression(), attrValue);
} catch (ValidationException e) {
throw new IllegalArgumentException("Could not validate expression " + computed.getExpression());
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyMatchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyMatchDAO.java
index add9784f7d..d086fc8ad0 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyMatchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyMatchDAO.java
@@ -35,6 +35,7 @@ import org.apache.commons.lang3.ClassUtils;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyMatchDAO;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
@@ -81,13 +82,16 @@ public class JPAAnyMatchDAO extends AbstractDAO<Any<?>> implements AnyMatchDAO {
protected final AnyUtilsFactory anyUtilsFactory;
+ protected final PlainAttrValidationManager validator;
+
public JPAAnyMatchDAO(
final UserDAO userDAO,
final GroupDAO groupDAO,
final AnyObjectDAO anyObjectDAO,
final RealmDAO realmDAO,
final PlainSchemaDAO plainSchemaDAO,
- final AnyUtilsFactory anyUtilsFactory) {
+ final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator) {
this.userDAO = userDAO;
this.groupDAO = groupDAO;
@@ -95,6 +99,7 @@ public class JPAAnyMatchDAO extends AbstractDAO<Any<?>> implements AnyMatchDAO {
this.realmDAO = realmDAO;
this.plainSchemaDAO = plainSchemaDAO;
this.anyUtilsFactory = anyUtilsFactory;
+ this.validator = validator;
}
/**
@@ -171,8 +176,9 @@ public class JPAAnyMatchDAO extends AbstractDAO<Any<?>> implements AnyMatchDAO {
}
if (match == null) {
- Optional<AnyCond> anyCond = cond.getLeaf(AnyCond.class);
- match = anyCond.map(value -> matches(any, value, not)).orElseGet(() -> cond.getLeaf(AttrCond.class).
+ match = cond.getLeaf(AnyCond.class).
+ map(value -> matches(any, value, not)).
+ orElseGet(() -> cond.getLeaf(AttrCond.class).
map(leaf -> matches(any, leaf, not)).
orElse(null));
}
@@ -197,12 +203,12 @@ public class JPAAnyMatchDAO extends AbstractDAO<Any<?>> implements AnyMatchDAO {
return false;
}
- protected static boolean matches(final Any<?> any, final AnyTypeCond cond, final boolean not) {
+ protected boolean matches(final Any<?> any, final AnyTypeCond cond, final boolean not) {
boolean equals = any.getType().getKey().equals(cond.getAnyTypeKey());
return not ? !equals : equals;
}
- protected static boolean matches(
+ protected boolean matches(
final GroupableRelatable<?, ?, ?, ?, ?> any, final RelationshipTypeCond cond, final boolean not) {
boolean found = any.getRelationships().stream().
@@ -284,7 +290,7 @@ public class JPAAnyMatchDAO extends AbstractDAO<Any<?>> implements AnyMatchDAO {
}
@SuppressWarnings({ "unchecked", "rawtypes" })
- protected static boolean matches(
+ protected boolean matches(
final List<? extends PlainAttrValue> anyAttrValues,
final PlainAttrValue attrValue,
final PlainSchema schema,
@@ -374,7 +380,7 @@ public class JPAAnyMatchDAO extends AbstractDAO<Any<?>> implements AnyMatchDAO {
&& cond.getType() != AttrCond.Type.ISNULL
&& cond.getType() != AttrCond.Type.ISNOTNULL) {
- ((JPAPlainSchema) schema).validator().validate(cond.getExpression(), attrValue);
+ validator.validate(schema, cond.getExpression(), attrValue);
}
} catch (ValidationException e) {
LOG.error("Could not validate expression '" + cond.getExpression() + '\'', e);
@@ -466,7 +472,7 @@ public class JPAAnyMatchDAO extends AbstractDAO<Any<?>> implements AnyMatchDAO {
&& cond.getType() != AttrCond.Type.ISNOTNULL) {
try {
- ((JPAPlainSchema) schema).validator().validate(cond.getExpression(), attrValue);
+ validator.validate(schema, cond.getExpression(), attrValue);
} catch (ValidationException e) {
LOG.error("Could not validate expression '" + cond.getExpression() + '\'', e);
return false;
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
index c87e434b4d..a1bca5e545 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
@@ -35,6 +35,7 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.rest.api.service.JAXRSService;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
@@ -79,9 +80,19 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
final AnyObjectDAO anyObjectDAO,
final PlainSchemaDAO plainSchemaDAO,
final EntityFactory entityFactory,
- final AnyUtilsFactory anyUtilsFactory) {
-
- super(realmDAO, dynRealmDAO, userDAO, groupDAO, anyObjectDAO, plainSchemaDAO, entityFactory, anyUtilsFactory);
+ final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator) {
+
+ super(
+ realmDAO,
+ dynRealmDAO,
+ userDAO,
+ groupDAO,
+ anyObjectDAO,
+ plainSchemaDAO,
+ entityFactory,
+ anyUtilsFactory,
+ validator);
}
protected String buildAdminRealmsFilter(
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
index aca6eee89d..d31abd15d6 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
@@ -27,6 +27,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceException;
@@ -38,11 +39,13 @@ import org.apache.syncope.common.lib.types.EntityViolationType;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
import org.apache.syncope.core.persistence.api.dao.AccessTokenDAO;
+import org.apache.syncope.core.persistence.api.dao.AccountRule;
import org.apache.syncope.core.persistence.api.dao.DelegationDAO;
import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
import org.apache.syncope.core.persistence.api.dao.FIQLQueryDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.PasswordRule;
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.RoleDAO;
@@ -93,6 +96,10 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
protected final SecurityProperties securityProperties;
+ protected final Map<String, AccountRule> perContextAccountRules = new ConcurrentHashMap<>();
+
+ protected final Map<String, PasswordRule> perContextPasswordRules = new ConcurrentHashMap<>();
+
public JPAUserDAO(
final AnyUtilsFactory anyUtilsFactory,
final PlainSchemaDAO plainSchemaDAO,
@@ -321,6 +328,42 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
return policies;
}
+ protected List<AccountRule> getAccountRules(final AccountPolicy policy) {
+ List<AccountRule> result = new ArrayList<>();
+
+ for (Implementation impl : policy.getRules()) {
+ try {
+ ImplementationManager.buildAccountRule(
+ impl,
+ () -> perContextAccountRules.get(impl.getKey()),
+ instance -> perContextAccountRules.put(impl.getKey(), instance)).
+ ifPresent(result::add);
+ } catch (Exception e) {
+ LOG.warn("While building {}", impl, e);
+ }
+ }
+
+ return result;
+ }
+
+ protected List<PasswordRule> getPasswordRules(final PasswordPolicy policy) {
+ List<PasswordRule> result = new ArrayList<>();
+
+ for (Implementation impl : policy.getRules()) {
+ try {
+ ImplementationManager.buildPasswordRule(
+ impl,
+ () -> perContextPasswordRules.get(impl.getKey()),
+ instance -> perContextPasswordRules.put(impl.getKey(), instance)).
+ ifPresent(result::add);
+ } catch (Exception e) {
+ LOG.warn("While building {}", impl, e);
+ }
+ }
+
+ return result;
+ }
+
@Transactional(readOnly = true)
@Override
public Pair<Boolean, Boolean> enforcePolicies(final User user) {
@@ -336,15 +379,13 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
throw new PasswordPolicyException("Password mandatory");
}
- for (Implementation impl : policy.getRules()) {
- ImplementationManager.buildPasswordRule(impl).ifPresent(rule -> {
- rule.enforce(user);
+ getPasswordRules(policy).forEach(rule -> {
+ rule.enforce(user);
- user.getLinkedAccounts().stream().
- filter(account -> account.getPassword() != null).
- forEach(rule::enforce);
- });
- }
+ user.getLinkedAccounts().stream().
+ filter(account -> account.getPassword() != null).
+ forEach(rule::enforce);
+ });
boolean matching = false;
if (policy.getHistoryLength() > 0) {
@@ -419,15 +460,13 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
});
} else {
for (AccountPolicy policy : accountPolicies) {
- for (Implementation impl : policy.getRules()) {
- ImplementationManager.buildAccountRule(impl).ifPresent(rule -> {
- rule.enforce(user);
+ getAccountRules(policy).forEach(rule -> {
+ rule.enforce(user);
- user.getLinkedAccounts().stream().
- filter(account -> account.getUsername() != null).
- forEach(rule::enforce);
- });
- }
+ user.getLinkedAccounts().stream().
+ filter(account -> account.getUsername() != null).
+ forEach(rule::enforce);
+ });
suspend |= user.getFailedLogins() != null && policy.getMaxAuthenticationAttempts() > 0
&& user.getFailedLogins() > policy.getMaxAuthenticationAttempts() && !user.isSuspended();
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java
index b3dfd3d213..0dc8ea0967 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java
@@ -26,6 +26,7 @@ import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotNull;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
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.PlainAttr;
@@ -65,11 +66,11 @@ public abstract class AbstractPlainAttr<O extends Any<?>> extends AbstractGenera
}
@Override
- public void add(final String value, final PlainAttrValue attrValue) {
+ public void add(final PlainAttrValidationManager validator, final String value, final PlainAttrValue attrValue) {
checkNonNullSchema();
attrValue.setAttr(this);
- getSchema().validator().validate(value, attrValue);
+ validator.validate(getSchema(), value, attrValue);
if (getSchema().isUniqueConstraint()) {
setUniqueValue((PlainAttrUniqueValue) attrValue);
@@ -82,7 +83,7 @@ public abstract class AbstractPlainAttr<O extends Any<?>> extends AbstractGenera
}
@Override
- public void add(final String value, final AnyUtils anyUtils) {
+ public void add(final PlainAttrValidationManager validator, final String value, final AnyUtils anyUtils) {
checkNonNullSchema();
PlainAttrValue attrValue;
@@ -93,7 +94,7 @@ public abstract class AbstractPlainAttr<O extends Any<?>> extends AbstractGenera
attrValue = anyUtils.newPlainAttrValue();
}
- add(value, attrValue);
+ add(validator, value, attrValue);
}
@Override
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 ae37005b57..786709523b 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
@@ -41,6 +41,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.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
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;
@@ -420,7 +421,12 @@ public class JPAAnyUtils implements AnyUtils {
@Transactional
@Override
- public void addAttr(final String key, final PlainSchema schema, final String value) {
+ public void addAttr(
+ final PlainAttrValidationManager validator,
+ final String key,
+ final PlainSchema schema,
+ final String value) {
+
Any any = dao().find(key);
Set<AnyTypeClass> typeOwnClasses = new HashSet<>();
@@ -439,7 +445,7 @@ public class JPAAnyUtils implements AnyUtils {
any.add(attr);
try {
- attr.add(value, this);
+ attr.add(validator, value, this);
dao().save(any);
} catch (InvalidPlainAttrValueException e) {
LOG.error("Invalid value for attribute {} and {}: {}", schema.getKey(), any, value, e);
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAPlainSchema.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAPlainSchema.java
index e795177db0..3299bd6612 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAPlainSchema.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAPlainSchema.java
@@ -27,18 +27,14 @@ import javax.persistence.Lob;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
-import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.common.lib.types.CipherAlgorithm;
import org.apache.syncope.common.lib.types.IdRepoImplementationType;
-import org.apache.syncope.core.persistence.api.attrvalue.validation.Validator;
import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
-import org.apache.syncope.core.persistence.jpa.attrvalue.validation.BasicValidator;
import org.apache.syncope.core.persistence.jpa.validation.entity.PlainSchemaCheck;
-import org.apache.syncope.core.spring.ImplementationManager;
@Entity
@Table(name = JPAPlainSchema.TABLE)
@@ -90,9 +86,6 @@ public class JPAPlainSchema extends AbstractSchema implements PlainSchema {
@OneToOne
private JPAImplementation validator;
- @Transient
- private Validator validatorImpl;
-
@Override
public AnyTypeClass getAnyTypeClass() {
return anyTypeClass;
@@ -154,27 +147,6 @@ public class JPAPlainSchema extends AbstractSchema implements PlainSchema {
this.readonly = readonly;
}
- public Validator validator() {
- if (validatorImpl != null) {
- return validatorImpl;
- }
-
- if (getValidator() != null) {
- try {
- validatorImpl = ImplementationManager.build(getValidator());
- } catch (Exception e) {
- LOG.error("While building {}", getValidator(), e);
- }
- }
-
- if (validatorImpl == null) {
- validatorImpl = new BasicValidator();
- }
- validatorImpl.setSchema(this);
-
- return validatorImpl;
- }
-
@Override
public Implementation getValidator() {
return validator;
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/JPAPlainAttrValidator.java
similarity index 96%
rename from core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java
rename to core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/JPAPlainAttrValidator.java
index 89ee1f8bda..1a66833a0f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/JPAPlainAttrValidator.java
@@ -22,7 +22,7 @@ import javax.validation.ConstraintValidatorContext;
import org.apache.syncope.common.lib.types.EntityViolationType;
import org.apache.syncope.core.persistence.api.entity.PlainAttr;
-public class PlainAttrValidator extends AbstractValidator<PlainAttrCheck, PlainAttr<?>> {
+public class JPAPlainAttrValidator extends AbstractValidator<PlainAttrCheck, PlainAttr<?>> {
@Override
public boolean isValid(final PlainAttr<?> attr, final ConstraintValidatorContext context) {
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java
index 4ae6eb5740..5fe4554400 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java
@@ -28,7 +28,7 @@ import javax.validation.Payload;
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
-@Constraint(validatedBy = PlainAttrValidator.class)
+@Constraint(validatedBy = JPAPlainAttrValidator.class)
@Documented
public @interface PlainAttrCheck {
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
index b2c4ceff53..8c68cdc608 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
@@ -36,6 +36,7 @@ import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.common.lib.types.CipherAlgorithm;
import org.apache.syncope.common.lib.types.EntityViolationType;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
@@ -67,6 +68,9 @@ public class PlainAttrTest extends AbstractTest {
@Autowired
private AnyTypeClassDAO anyTypeClassDAO;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
@Tag("plainAttrTable")
@Test
public void findByKey() {
@@ -98,15 +102,15 @@ public class PlainAttrTest extends AbstractTest {
Exception thrown = null;
try {
- attr.add("john.doe@gmail.com", anyUtilsFactory.getInstance(AnyTypeKind.USER));
- attr.add("mario.rossi@gmail.com", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "john.doe@gmail.com", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "mario.rossi@gmail.com", anyUtilsFactory.getInstance(AnyTypeKind.USER));
} catch (ValidationException e) {
thrown = e;
}
assertNull(thrown);
try {
- attr.add("http://www.apache.org", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "http://www.apache.org", anyUtilsFactory.getInstance(AnyTypeKind.USER));
} catch (ValidationException e) {
thrown = e;
}
@@ -130,13 +134,13 @@ public class PlainAttrTest extends AbstractTest {
Exception thrown = null;
try {
- attribute.add("A", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attribute.add(validator, "A", anyUtilsFactory.getInstance(AnyTypeKind.USER));
} catch (ValidationException e) {
thrown = e;
}
assertNotNull(thrown);
- attribute.add("M", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attribute.add(validator, "M", anyUtilsFactory.getInstance(AnyTypeKind.USER));
InvalidEntityException iee = null;
try {
@@ -225,7 +229,7 @@ public class PlainAttrTest extends AbstractTest {
UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
attr.setOwner(user);
attr.setSchema(obscureSchema);
- attr.add("testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
user.add(attr);
userDAO.save(user);
@@ -255,7 +259,7 @@ public class PlainAttrTest extends AbstractTest {
UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
attr.setSchema(obscureWithKeyAsSysprop);
- attr.add("testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
assertEquals(Encryptor.getInstance(obscureSchema.getSecretKey()).
encode("testvalue", obscureSchema.getCipherAlgorithm()), attr.getValues().get(0).getStringValue());
@@ -274,8 +278,8 @@ public class PlainAttrTest extends AbstractTest {
UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
attr.setSchema(obscureWithDecodeConversionPattern);
- attr.add("testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
-
+ attr.add(validator, "testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+
assertEquals(Encryptor.getInstance(obscureWithDecodeConversionPattern.getSecretKey()).
encode("testvalue", obscureWithDecodeConversionPattern.getCipherAlgorithm()),
attr.getValues().get(0).getStringValue());
@@ -302,7 +306,7 @@ public class PlainAttrTest extends AbstractTest {
UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
attr.setOwner(user);
attr.setSchema(photoSchema);
- attr.add(photoB64Value, anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, photoB64Value, anyUtilsFactory.getInstance(AnyTypeKind.USER));
user.add(attr);
userDAO.save(user);
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
index a3ee8a9a49..67fd767e93 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/AnySearchTest.java
@@ -32,6 +32,7 @@ import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
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.PlainSchemaDAO;
@@ -76,6 +77,9 @@ public class AnySearchTest extends AbstractTest {
@Autowired
private PlainSchemaDAO plainSchemaDAO;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
@Test
public void searchByDynMembership() {
// 1. create role with dynamic membership
@@ -204,14 +208,14 @@ public class AnySearchTest extends AbstractTest {
GPlainAttr title = entityFactory.newEntity(GPlainAttr.class);
title.setOwner(group);
title.setSchema(plainSchemaDAO.find("title"));
- title.add("syncope's group", anyUtilsFactory.getInstance(AnyTypeKind.GROUP));
+ title.add(validator, "syncope's group", anyUtilsFactory.getInstance(AnyTypeKind.GROUP));
group.add(title);
// unique
GPlainAttr originalName = entityFactory.newEntity(GPlainAttr.class);
originalName.setOwner(group);
originalName.setSchema(plainSchemaDAO.find("originalName"));
- originalName.add("syncope's group", anyUtilsFactory.getInstance(AnyTypeKind.GROUP));
+ originalName.add(validator, "syncope's group", anyUtilsFactory.getInstance(AnyTypeKind.GROUP));
group.add(originalName);
groupDAO.save(group);
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
index c9c1c7d159..c45a8329d3 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
@@ -35,6 +35,7 @@ import javax.persistence.Query;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
@@ -84,6 +85,9 @@ public class GroupTest extends AbstractTest {
@Autowired
private AnyTypeClassDAO anyTypeClassDAO;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
@Test
public void saveWithTwoOwners() {
assertThrows(InvalidEntityException.class, () -> {
@@ -205,7 +209,7 @@ public class GroupTest extends AbstractTest {
UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
attr.setOwner(user);
attr.setSchema(plainSchemaDAO.find("cool"));
- attr.add("true", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "true", anyUtilsFactory.getInstance(AnyTypeKind.USER));
user.add(attr);
user = userDAO.save(user);
@@ -304,7 +308,7 @@ public class GroupTest extends AbstractTest {
APlainAttr attr = entityFactory.newEntity(APlainAttr.class);
attr.setOwner(anyObject);
attr.setSchema(plainSchemaDAO.find("model"));
- attr.add("Canon MFC8030", anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT));
+ attr.add(validator, "Canon MFC8030", anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT));
anyObject.add(attr);
anyObject = anyObjectDAO.save(anyObject);
@@ -382,14 +386,14 @@ public class GroupTest extends AbstractTest {
GPlainAttr title = entityFactory.newEntity(GPlainAttr.class);
title.setOwner(group);
title.setSchema(plainSchemaDAO.find("title"));
- title.add("syncope's group", anyUtilsFactory.getInstance(AnyTypeKind.GROUP));
+ title.add(validator, "syncope's group", anyUtilsFactory.getInstance(AnyTypeKind.GROUP));
group.add(title);
// unique
GPlainAttr originalName = entityFactory.newEntity(GPlainAttr.class);
originalName.setOwner(group);
originalName.setSchema(plainSchemaDAO.find("originalName"));
- originalName.add("syncope's group", anyUtilsFactory.getInstance(AnyTypeKind.GROUP));
+ originalName.add(validator, "syncope's group", anyUtilsFactory.getInstance(AnyTypeKind.GROUP));
group.add(originalName);
groupDAO.save(group);
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/RoleTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/RoleTest.java
index 402860d27b..b857573862 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/RoleTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/RoleTest.java
@@ -32,6 +32,7 @@ import java.util.Set;
import javax.persistence.Query;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
import org.apache.syncope.core.persistence.api.dao.DelegationDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
@@ -71,6 +72,9 @@ public class RoleTest extends AbstractTest {
@Autowired
private DelegationDAO delegationDAO;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
/**
* Static copy of {@link org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO} method with same signature:
* required for avoiding creating new transaction - good for general use case but bad for the way how
@@ -106,7 +110,7 @@ public class RoleTest extends AbstractTest {
UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
attr.setOwner(user);
attr.setSchema(plainSchemaDAO.find("cool"));
- attr.add("true", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "true", anyUtilsFactory.getInstance(AnyTypeKind.USER));
user.add(attr);
user = userDAO.save(user);
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
index 8f5c75a8f5..46c35c87c1 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
@@ -32,6 +32,7 @@ import java.util.UUID;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.CipherAlgorithm;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.ApplicationDAO;
import org.apache.syncope.core.persistence.api.dao.DelegationDAO;
@@ -96,6 +97,9 @@ public class UserTest extends AbstractTest {
@Autowired
private RoleDAO roleDAO;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
@Test
public void delete() {
List<UMembership> memberships = groupDAO.findUMemberships(groupDAO.findByName("managingDirector"));
@@ -169,7 +173,7 @@ public class UserTest extends AbstractTest {
UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
attr.setOwner(user);
attr.setSchema(plainSchemaDAO.find("obscure"));
- attr.add("testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
user.add(attr);
// add 'obscure' to user (via 'artDirector' membership): does not work because 'obscure' is from 'other'
@@ -183,7 +187,7 @@ public class UserTest extends AbstractTest {
attr.setOwner(user);
attr.setMembership(membership);
attr.setSchema(plainSchemaDAO.find("obscure"));
- attr.add("testvalue2", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "testvalue2", anyUtilsFactory.getInstance(AnyTypeKind.USER));
user.add(attr);
try {
@@ -204,7 +208,7 @@ public class UserTest extends AbstractTest {
UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
attr.setOwner(user);
attr.setSchema(plainSchemaDAO.find("obscure"));
- attr.add("testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
user.add(attr);
// add 'obscure' (via 'additional' membership): that group defines type extension with classes 'other' and 'csv'
@@ -217,7 +221,7 @@ public class UserTest extends AbstractTest {
attr.setOwner(user);
attr.setMembership(membership);
attr.setSchema(plainSchemaDAO.find("obscure"));
- attr.add("testvalue2", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ attr.add(validator, "testvalue2", anyUtilsFactory.getInstance(AnyTypeKind.USER));
user.add(attr);
userDAO.save(user);
@@ -260,7 +264,7 @@ public class UserTest extends AbstractTest {
attr.setAccount(account);
account.add(attr);
attr.setSchema(plainSchemaDAO.find("obscure"));
- attr.add("testvalue", anyUtils);
+ attr.add(validator, "testvalue", anyUtils);
user = userDAO.save(user);
entityManager().flush();
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 0d41fc8f28..0acb0a151c 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -632,7 +632,7 @@ under the License.
connectorName="net.tirasa.connid.bundles.ldap.LdapConnector"
version="${connid.ldap.version}"
jsonConf='[{"schema":{"name":"host","type":"java.lang.String","required":true,"order":1,"confidential":false,"defaultValues":[]},"values":["localhost"],"overridable":false},{"schema":{"name":"port","type":"int","required":false,"order":2,"confidential":false,"defaultValues":[389]},"values":[1389],"overridable":false},{"schema":{"name":"ssl","type":"boolean","required":false,"order":3,"confidential":false,"defaultValues":[false]},"values":["false"],"overridable":false},{"s [...]
- capabilities='["CREATE","UPDATE","DELETE","SEARCH"]'/>
+ capabilities='["CREATE","UPDATE","UPDATE_DELTA","DELETE","SEARCH"]'/>
<ConnInstance id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" displayName="H2-test2"
adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
@@ -657,7 +657,7 @@ under the License.
connectorName="net.tirasa.connid.bundles.db.scriptedsql.ScriptedSQLConnector"
displayName="Scripted SQL" version="${connid.database.version}"
jsonConf='[{"schema":{"name":"updateScriptFileName","displayName":"updateScriptFileName","helpMessage":"updateScriptFileName","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":[]},"overridable":false,"values":["${conf.directory}/scriptedsql/UpdateScript.groovy"]},{"schem [...]
- capabilities='["CREATE","UPDATE","DELETE","SEARCH","SYNC"]'/>
+ capabilities='["CREATE","UPDATE","UPDATE_DELTA","DELETE","SEARCH","SYNC"]'/>
<ConnInstance id="44c02549-19c3-483c-8025-4919c3283c37" bundlename="net.tirasa.connid.bundles.rest"
adminRealm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
index d03331d955..68cc8a56bc 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
@@ -236,7 +236,7 @@ public class ConnectorFacadeProxy implements Connector {
Set<AttributeDelta> result = null;
- if (connInstance.getCapabilities().contains(ConnectorCapability.UPDATE)) {
+ if (connInstance.getCapabilities().contains(ConnectorCapability.UPDATE_DELTA)) {
propagationAttempted.set(true);
Future<Set<AttributeDelta>> future =
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java
index 36a44dfbbc..5554f89d87 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java
@@ -34,6 +34,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
import org.apache.syncope.common.lib.LogOutputStream;
import org.apache.syncope.core.persistence.api.DomainHolder;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AccessTokenDAO;
import org.apache.syncope.core.persistence.api.dao.AnyMatchDAO;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
@@ -624,7 +625,8 @@ public class ProvisioningContext {
final NotificationManager notificationManager,
final AuditManager auditManager,
final TaskDataBinder taskDataBinder,
- final OutboundMatcher outboundMatcher) {
+ final OutboundMatcher outboundMatcher,
+ final PlainAttrValidationManager validator) {
return new PriorityPropagationTaskExecutor(
connectorManager,
@@ -642,6 +644,7 @@ public class ProvisioningContext {
taskUtilsFactory,
entityFactory,
outboundMatcher,
+ validator,
propagationTaskExecutorAsyncExecutor);
}
@@ -837,7 +840,8 @@ public class ProvisioningContext {
final VirAttrHandler virAttrHandler,
final MappingManager mappingManager,
final IntAttrNameParser intAttrNameParser,
- final OutboundMatcher outboundMatcher) {
+ final OutboundMatcher outboundMatcher,
+ final PlainAttrValidationManager validator) {
return new AnyObjectDataBinderImpl(
anyTypeDAO,
@@ -857,7 +861,8 @@ public class ProvisioningContext {
virAttrHandler,
mappingManager,
intAttrNameParser,
- outboundMatcher);
+ outboundMatcher,
+ validator);
}
@ConditionalOnMissingBean
@@ -995,7 +1000,8 @@ public class ProvisioningContext {
final VirAttrHandler virAttrHandler,
final MappingManager mappingManager,
final IntAttrNameParser intAttrNameParser,
- final OutboundMatcher outboundMatcher) {
+ final OutboundMatcher outboundMatcher,
+ final PlainAttrValidationManager validator) {
return new GroupDataBinderImpl(
anyTypeDAO,
@@ -1016,7 +1022,8 @@ public class ProvisioningContext {
mappingManager,
intAttrNameParser,
outboundMatcher,
- searchCondVisitor);
+ searchCondVisitor,
+ validator);
}
@ConditionalOnMissingBean
@@ -1237,6 +1244,7 @@ public class ProvisioningContext {
final MappingManager mappingManager,
final IntAttrNameParser intAttrNameParser,
final OutboundMatcher outboundMatcher,
+ final PlainAttrValidationManager validator,
final RoleDAO roleDAO,
final SecurityQuestionDAO securityQuestionDAO,
final ApplicationDAO applicationDAO,
@@ -1263,6 +1271,7 @@ public class ProvisioningContext {
mappingManager,
intAttrNameParser,
outboundMatcher,
+ validator,
roleDAO,
securityQuestionDAO,
applicationDAO,
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index 65d7100068..b728ec7759 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -47,6 +47,7 @@ import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
@@ -135,6 +136,8 @@ abstract class AbstractAnyDataBinder {
protected final OutboundMatcher outboundMatcher;
+ protected final PlainAttrValidationManager validator;
+
protected AbstractAnyDataBinder(
final AnyTypeDAO anyTypeDAO,
final RealmDAO realmDAO,
@@ -153,7 +156,8 @@ abstract class AbstractAnyDataBinder {
final VirAttrHandler virAttrHandler,
final MappingManager mappingManager,
final IntAttrNameParser intAttrNameParser,
- final OutboundMatcher outboundMatcher) {
+ final OutboundMatcher outboundMatcher,
+ final PlainAttrValidationManager validator) {
this.anyTypeDAO = anyTypeDAO;
this.realmDAO = realmDAO;
@@ -173,6 +177,7 @@ abstract class AbstractAnyDataBinder {
this.mappingManager = mappingManager;
this.intAttrNameParser = intAttrNameParser;
this.outboundMatcher = outboundMatcher;
+ this.validator = validator;
}
protected void setRealm(final Any<?> any, final AnyUR anyUR) {
@@ -260,7 +265,7 @@ abstract class AbstractAnyDataBinder {
LOG.debug("Null value for {}, ignoring", schema.getKey());
} else {
try {
- attr.add(value, anyUtils);
+ attr.add(validator, value, anyUtils);
} catch (InvalidPlainAttrValueException e) {
String valueToPrint = value.length() > 40
? value.substring(0, 20) + "..."
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
index 11f9b1d433..643f2e7c19 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -39,6 +39,7 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
@@ -93,7 +94,8 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
final VirAttrHandler virAttrHandler,
final MappingManager mappingManager,
final IntAttrNameParser intAttrNameParser,
- final OutboundMatcher outboundMatcher) {
+ final OutboundMatcher outboundMatcher,
+ final PlainAttrValidationManager validator) {
super(anyTypeDAO,
realmDAO,
@@ -112,7 +114,8 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
virAttrHandler,
mappingManager,
intAttrNameParser,
- outboundMatcher);
+ outboundMatcher,
+ validator);
}
@Transactional(readOnly = true)
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
index d33fd4e00f..b49e90a43b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
@@ -35,6 +35,7 @@ import org.apache.syncope.common.lib.to.TypeExtensionTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
@@ -96,7 +97,8 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
final MappingManager mappingManager,
final IntAttrNameParser intAttrNameParser,
final OutboundMatcher outboundMatcher,
- final SearchCondVisitor searchCondVisitor) {
+ final SearchCondVisitor searchCondVisitor,
+ final PlainAttrValidationManager validator) {
super(anyTypeDAO,
realmDAO,
@@ -115,7 +117,8 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
virAttrHandler,
mappingManager,
intAttrNameParser,
- outboundMatcher);
+ outboundMatcher,
+ validator);
this.searchCondVisitor = searchCondVisitor;
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
index d5b6554407..c7dad2ecec 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
@@ -28,7 +28,7 @@ import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.IdMImplementationType;
import org.apache.syncope.common.lib.types.IdRepoImplementationType;
import org.apache.syncope.common.lib.types.ImplementationEngine;
-import org.apache.syncope.core.persistence.api.attrvalue.validation.Validator;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValueValidator;
import org.apache.syncope.core.persistence.api.dao.AccountRule;
import org.apache.syncope.core.persistence.api.dao.PasswordRule;
import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
@@ -138,7 +138,7 @@ public class ImplementationDataBinderImpl implements ImplementationDataBinder {
break;
case IdRepoImplementationType.VALIDATOR:
- base = Validator.class;
+ base = PlainAttrValueValidator.class;
break;
case IdRepoImplementationType.RECIPIENTS_PROVIDER:
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index c6010e891d..b86f460a3a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -352,10 +352,10 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
resource.setProvisioningTraceLevel(resourceTO.getProvisioningTraceLevel());
resource.setPasswordPolicy(resourceTO.getPasswordPolicy() == null
- ? null : (PasswordPolicy) policyDAO.find(resourceTO.getPasswordPolicy()));
+ ? null : policyDAO.<PasswordPolicy>find(resourceTO.getPasswordPolicy()));
resource.setAccountPolicy(resourceTO.getAccountPolicy() == null
- ? null : (AccountPolicy) policyDAO.find(resourceTO.getAccountPolicy()));
+ ? null : policyDAO.<AccountPolicy>find(resourceTO.getAccountPolicy()));
if (resource.getPropagationPolicy() != null
&& !resource.getPropagationPolicy().getKey().equals(resourceTO.getPropagationPolicy())) {
@@ -363,13 +363,13 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
propagationTaskExecutor.expireRetryTemplate(resource.getKey());
}
resource.setPropagationPolicy(resourceTO.getPropagationPolicy() == null
- ? null : (PropagationPolicy) policyDAO.find(resourceTO.getPropagationPolicy()));
+ ? null : policyDAO.<PropagationPolicy>find(resourceTO.getPropagationPolicy()));
resource.setPullPolicy(resourceTO.getPullPolicy() == null
- ? null : (PullPolicy) policyDAO.find(resourceTO.getPullPolicy()));
+ ? null : policyDAO.<PullPolicy>find(resourceTO.getPullPolicy()));
resource.setPushPolicy(resourceTO.getPushPolicy() == null
- ? null : (PushPolicy) policyDAO.find(resourceTO.getPushPolicy()));
+ ? null : policyDAO.<PushPolicy>find(resourceTO.getPushPolicy()));
if (resourceTO.getProvisionSorter() == null) {
resource.setProvisionSorter(null);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index 719c650cfb..15be775af5 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -48,6 +48,7 @@ import org.apache.syncope.common.lib.types.CipherAlgorithm;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AccessTokenDAO;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
@@ -131,6 +132,7 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
final MappingManager mappingManager,
final IntAttrNameParser intAttrNameParser,
final OutboundMatcher outboundMatcher,
+ final PlainAttrValidationManager validator,
final RoleDAO roleDAO,
final SecurityQuestionDAO securityQuestionDAO,
final ApplicationDAO applicationDAO,
@@ -156,7 +158,8 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
virAttrHandler,
mappingManager,
intAttrNameParser,
- outboundMatcher);
+ outboundMatcher,
+ validator);
this.roleDAO = roleDAO;
this.securityQuestionDAO = securityQuestionDAO;
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/DefaultNotificationManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/DefaultNotificationManager.java
index 5705deb22a..f16b5d0a8a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/DefaultNotificationManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/DefaultNotificationManager.java
@@ -121,6 +121,8 @@ public class DefaultNotificationManager implements NotificationManager {
protected final SearchCondVisitor searchCondVisitor;
+ protected Optional<RecipientsProvider> perContextRecipientsProvider = Optional.empty();
+
public DefaultNotificationManager(
final DerSchemaDAO derSchemaDAO,
final VirSchemaDAO virSchemaDAO,
@@ -216,8 +218,11 @@ public class DefaultNotificationManager implements NotificationManager {
if (notification.getRecipientsProvider() != null) {
try {
- RecipientsProvider recipientsProvider =
- ImplementationManager.build(notification.getRecipientsProvider());
+ RecipientsProvider recipientsProvider = ImplementationManager.build(
+ notification.getRecipientsProvider(),
+ () -> perContextRecipientsProvider.orElse(null),
+ instance -> perContextRecipientsProvider = Optional.of(instance));
+
recipientEmails.addAll(recipientsProvider.provideRecipients(notification));
} catch (Exception e) {
LOG.error("While building {}", notification.getRecipientsProvider(), e);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
index 2db1e6ece5..f4fcd7ab8e 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
@@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -39,6 +40,7 @@ import org.apache.syncope.common.lib.types.AuditElements.Result;
import org.apache.syncope.common.lib.types.ExecStatus;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.common.lib.types.TraceLevel;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
@@ -127,6 +129,10 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
protected final OutboundMatcher outboundMatcher;
+ protected final PlainAttrValidationManager validator;
+
+ protected final Map<String, PropagationActions> perContextActions = new ConcurrentHashMap<>();
+
public AbstractPropagationTaskExecutor(
final ConnectorManager connectorManager,
final ConnObjectUtils connObjectUtils,
@@ -142,7 +148,8 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
final AnyUtilsFactory anyUtilsFactory,
final TaskUtilsFactory taskUtilsFactory,
final EntityFactory entityFactory,
- final OutboundMatcher outboundMatcher) {
+ final OutboundMatcher outboundMatcher,
+ final PlainAttrValidationManager validator) {
this.connectorManager = connectorManager;
this.connObjectUtils = connObjectUtils;
@@ -159,6 +166,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
this.taskUtilsFactory = taskUtilsFactory;
this.entityFactory = entityFactory;
this.outboundMatcher = outboundMatcher;
+ this.validator = validator;
}
@Override
@@ -171,7 +179,10 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
resource.getPropagationActions().forEach(impl -> {
try {
- result.add(ImplementationManager.build(impl));
+ result.add(ImplementationManager.build(
+ impl,
+ () -> perContextActions.get(impl.getKey()),
+ instance -> perContextActions.put(impl.getKey(), instance)));
} catch (Exception e) {
LOG.error("While building {}", impl, e);
}
@@ -193,7 +204,10 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
taskInfo.getResource().getProvision(taskInfo.getAnyType()).
filter(provision -> provision.getUidOnCreate() != null).
ifPresent(provision -> anyUtilsFactory.getInstance(taskInfo.getAnyTypeKind()).addAttr(
- taskInfo.getEntityKey(), plainSchemaDAO.find(provision.getUidOnCreate()), result.getUidValue()));
+ validator,
+ taskInfo.getEntityKey(),
+ plainSchemaDAO.find(provision.getUidOnCreate()),
+ result.getUidValue()));
return result;
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AzurePropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AzurePropagationActions.java
index 31fec8e831..c90a0e9c2f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AzurePropagationActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AzurePropagationActions.java
@@ -24,6 +24,8 @@ import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.core.persistence.api.entity.task.PropagationData;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
+import org.apache.syncope.core.spring.implementation.InstanceScope;
+import org.apache.syncope.core.spring.implementation.SyncopeImplementation;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.identityconnectors.framework.common.objects.Name;
@@ -37,6 +39,7 @@ import org.springframework.transaction.annotation.Transactional;
*
* It ensures to send the configured e-mail address as {@code __NAME__}.
*/
+@SyncopeImplementation(scope = InstanceScope.PER_CONTEXT)
public class AzurePropagationActions implements PropagationActions {
protected static final Logger LOG = LoggerFactory.getLogger(AzurePropagationActions.class);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DBPasswordPropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DBPasswordPropagationActions.java
index a0e154f31c..e36a73ee45 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DBPasswordPropagationActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DBPasswordPropagationActions.java
@@ -30,6 +30,8 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
+import org.apache.syncope.core.spring.implementation.InstanceScope;
+import org.apache.syncope.core.spring.implementation.SyncopeImplementation;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
@@ -43,6 +45,7 @@ import org.springframework.transaction.annotation.Transactional;
* added a password. The CipherAlgorithm associated with the password must match the password
* cipher algorithm property of the DB Connector.
*/
+@SyncopeImplementation(scope = InstanceScope.PER_CONTEXT)
public class DBPasswordPropagationActions implements PropagationActions {
protected static final String CLEARTEXT = "CLEARTEXT";
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
index 39ede6a0b1..6bb431bc78 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
@@ -18,9 +18,6 @@
*/
package org.apache.syncope.core.provisioning.java.propagation;
-import static org.apache.syncope.core.provisioning.api.propagation.PropagationManager.MANDATORY_MISSING_ATTR_NAME;
-import static org.apache.syncope.core.provisioning.api.propagation.PropagationManager.MANDATORY_NULL_OR_EMPTY_ATTR_NAME;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java
index 846994d8bb..d1a869fdbe 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java
@@ -25,6 +25,8 @@ import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.core.persistence.api.entity.task.PropagationData;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
+import org.apache.syncope.core.spring.implementation.InstanceScope;
+import org.apache.syncope.core.spring.implementation.SyncopeImplementation;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.identityconnectors.framework.common.objects.Name;
@@ -38,6 +40,7 @@ import org.springframework.transaction.annotation.Transactional;
*
* It ensures to send the configured e-mail address as {@code __NAME__}.
*/
+@SyncopeImplementation(scope = InstanceScope.PER_CONTEXT)
public class GoogleAppsPropagationActions implements PropagationActions {
protected static final Logger LOG = LoggerFactory.getLogger(GoogleAppsPropagationActions.class);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
index bb590cc393..9cb4215b3f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java
@@ -43,6 +43,8 @@ import org.apache.syncope.core.provisioning.api.DerAttrHandler;
import org.apache.syncope.core.provisioning.api.jexl.JexlUtils;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
+import org.apache.syncope.core.spring.implementation.InstanceScope;
+import org.apache.syncope.core.spring.implementation.SyncopeImplementation;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
import org.identityconnectors.framework.common.objects.AttributeDeltaBuilder;
import org.identityconnectors.framework.common.objects.AttributeDeltaUtil;
@@ -58,6 +60,7 @@ import org.springframework.transaction.annotation.Transactional;
*
* @see org.apache.syncope.core.provisioning.java.pushpull.LDAPMembershipPullActions
*/
+@SyncopeImplementation(scope = InstanceScope.PER_CONTEXT)
public class LDAPMembershipPropagationActions implements PropagationActions {
protected static final Logger LOG = LoggerFactory.getLogger(LDAPMembershipPropagationActions.class);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPPasswordPropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPPasswordPropagationActions.java
index 76ab4355d4..eb3cee8806 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPPasswordPropagationActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPPasswordPropagationActions.java
@@ -30,6 +30,8 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
+import org.apache.syncope.core.spring.implementation.InstanceScope;
+import org.apache.syncope.core.spring.implementation.SyncopeImplementation;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
@@ -43,6 +45,7 @@ import org.springframework.transaction.annotation.Transactional;
* added a password. The CipherAlgorithm associated with the password must match the password
* hash algorithm property of the LDAP Connector.
*/
+@SyncopeImplementation(scope = InstanceScope.PER_CONTEXT)
public class LDAPPasswordPropagationActions implements PropagationActions {
private static final String CLEARTEXT = "CLEARTEXT";
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java
index 5daf4bf5f3..5fb86aa96d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java
@@ -28,6 +28,7 @@ import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import org.apache.syncope.common.lib.types.ExecStatus;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
@@ -102,6 +103,7 @@ public class PriorityPropagationTaskExecutor extends AbstractPropagationTaskExec
final TaskUtilsFactory taskUtilsFactory,
final EntityFactory entityFactory,
final OutboundMatcher outboundMatcher,
+ final PlainAttrValidationManager validator,
final ThreadPoolTaskExecutor taskExecutor) {
super(connectorManager,
@@ -118,7 +120,8 @@ public class PriorityPropagationTaskExecutor extends AbstractPropagationTaskExec
anyUtilsFactory,
taskUtilsFactory,
entityFactory,
- outboundMatcher);
+ outboundMatcher,
+ validator);
this.taskExecutor = taskExecutor;
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractProvisioningJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractProvisioningJobDelegate.java
index fe113c6558..c429d09c12 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractProvisioningJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractProvisioningJobDelegate.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.to.Mapping;
import org.apache.syncope.common.lib.to.Provision;
@@ -36,8 +37,10 @@ import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
import org.apache.syncope.core.provisioning.api.Connector;
import org.apache.syncope.core.provisioning.api.ConnectorManager;
+import org.apache.syncope.core.provisioning.api.ProvisionSorter;
import org.apache.syncope.core.provisioning.java.job.AbstractSchedTaskJobDelegate;
import org.apache.syncope.core.provisioning.java.job.TaskJob;
+import org.apache.syncope.core.spring.ImplementationManager;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -105,6 +108,26 @@ public abstract class AbstractProvisioningJobDelegate<T extends ProvisioningTask
@Autowired
protected PolicyDAO policyDAO;
+ protected Optional<ProvisionSorter> perContextProvisionSorter = Optional.empty();
+
+ protected ProvisionSorter getProvisionSorter(final T task) {
+ if (task.getResource().getProvisionSorter() != null) {
+ try {
+ return ImplementationManager.build(
+ task.getResource().getProvisionSorter(),
+ () -> perContextProvisionSorter.orElse(null),
+ instance -> perContextProvisionSorter = Optional.of(instance));
+ } catch (Exception e) {
+ LOG.error("While building {}", task.getResource().getProvisionSorter(), e);
+ }
+ }
+
+ if (perContextProvisionSorter.isEmpty()) {
+ perContextProvisionSorter = Optional.of(new DefaultProvisionSorter());
+ }
+ return perContextProvisionSorter.get();
+ }
+
/**
* Create a textual report of the provisioning operation, based on the trace level.
*
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java
index 8ca7faeb21..dd5af11ef2 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java
@@ -21,8 +21,10 @@ package org.apache.syncope.core.provisioning.java.pushpull;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.syncope.common.lib.to.Item;
@@ -106,6 +108,8 @@ public class InboundMatcher {
protected final AnyUtilsFactory anyUtilsFactory;
+ protected final Map<String, PullCorrelationRule> perContextPullCorrelationRules = new ConcurrentHashMap<>();
+
public InboundMatcher(
final UserDAO userDAO,
final AnyObjectDAO anyObjectDAO,
@@ -130,13 +134,6 @@ public class InboundMatcher {
this.anyUtilsFactory = anyUtilsFactory;
}
- protected List<Implementation> getTransformers(final Item item) {
- return item.getTransformers().stream().
- map(implementationDAO::find).
- filter(Objects::nonNull).
- collect(Collectors.toList());
- }
-
public Optional<PullMatch> match(
final AnyType anyType,
final String nameValue,
@@ -212,6 +209,13 @@ public class InboundMatcher {
return result;
}
+ protected List<Implementation> getTransformers(final Item item) {
+ return item.getTransformers().stream().
+ map(implementationDAO::find).
+ filter(Objects::nonNull).
+ collect(Collectors.toList());
+ }
+
public List<PullMatch> matchByConnObjectKeyValue(
final Item connObjectKeyItem,
final String connObjectKeyValue,
@@ -353,6 +357,27 @@ public class InboundMatcher {
return result;
}
+ protected Optional<PullCorrelationRule> rule(final ExternalResource resource, final Provision provision) {
+ Optional<? extends PullCorrelationRuleEntity> correlationRule = resource.getPullPolicy() == null
+ ? Optional.empty()
+ : resource.getPullPolicy().getCorrelationRule(provision.getAnyType());
+
+ Optional<PullCorrelationRule> rule = Optional.empty();
+ if (correlationRule.isPresent()) {
+ Implementation impl = correlationRule.get().getImplementation();
+ try {
+ rule = ImplementationManager.buildPullCorrelationRule(
+ impl,
+ () -> perContextPullCorrelationRules.get(impl.getKey()),
+ instance -> perContextPullCorrelationRules.put(impl.getKey(), instance));
+ } catch (Exception e) {
+ LOG.error("While building {}", impl, e);
+ }
+ }
+
+ return rule;
+ }
+
/**
* Finds internal entities based on external attributes and mapping.
*
@@ -368,18 +393,7 @@ public class InboundMatcher {
final Provision provision,
final AnyTypeKind anyTypeKind) {
- Optional<? extends PullCorrelationRuleEntity> correlationRule = resource.getPullPolicy() == null
- ? Optional.empty()
- : resource.getPullPolicy().getCorrelationRule(provision.getAnyType());
-
- Optional<PullCorrelationRule> rule = Optional.empty();
- if (correlationRule.isPresent()) {
- try {
- rule = ImplementationManager.buildPullCorrelationRule(correlationRule.get().getImplementation());
- } catch (Exception e) {
- LOG.error("While building {}", correlationRule.get().getImplementation(), e);
- }
- }
+ Optional<PullCorrelationRule> rule = rule(resource, provision);
List<PullMatch> result = List.of();
try {
@@ -470,7 +484,7 @@ public class InboundMatcher {
case "name":
if (orgUnit.isIgnoreCaseMatch()) {
- final String realmName = connObjectKey;
+ String realmName = connObjectKey;
result.addAll(realmDAO.findAll().stream().
filter(r -> r.getName().equalsIgnoreCase(realmName)).collect(Collectors.toList()));
} else {
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java
index 89da2ee27c..2c78a12d15 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java
@@ -22,8 +22,10 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.syncope.common.lib.to.Item;
@@ -35,6 +37,7 @@ 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.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.policy.PushCorrelationRuleEntity;
import org.apache.syncope.core.provisioning.api.Connector;
@@ -69,6 +72,10 @@ public class OutboundMatcher {
protected final VirAttrHandler virAttrHandler;
+ protected final Map<String, PropagationActions> perContextActions = new ConcurrentHashMap<>();
+
+ protected final Map<String, PushCorrelationRule> perContextPushCorrelationRules = new ConcurrentHashMap<>();
+
public OutboundMatcher(
final MappingManager mappingManager,
final UserDAO userDAO,
@@ -90,10 +97,14 @@ public class OutboundMatcher {
Optional<PushCorrelationRule> rule = Optional.empty();
if (correlationRule.isPresent()) {
+ Implementation impl = correlationRule.get().getImplementation();
try {
- rule = ImplementationManager.buildPushCorrelationRule(correlationRule.get().getImplementation());
+ rule = ImplementationManager.buildPushCorrelationRule(
+ impl,
+ () -> perContextPushCorrelationRules.get(impl.getKey()),
+ instance -> perContextPushCorrelationRules.put(impl.getKey(), instance));
} catch (Exception e) {
- LOG.error("While building {}", correlationRule.get().getImplementation(), e);
+ LOG.error("While building {}", impl, e);
}
}
@@ -160,6 +171,23 @@ public class OutboundMatcher {
return result;
}
+ protected List<PropagationActions> getPropagationActions(final ExternalResource resource) {
+ List<PropagationActions> result = new ArrayList<>();
+
+ resource.getPropagationActions().forEach(impl -> {
+ try {
+ result.add(ImplementationManager.build(
+ impl,
+ () -> perContextActions.get(impl.getKey()),
+ instance -> perContextActions.put(impl.getKey(), instance)));
+ } catch (Exception e) {
+ LOG.error("While building {}", impl, e);
+ }
+ });
+
+ return result;
+ }
+
@Transactional(readOnly = true)
public List<ConnectorObject> match(
final Connector connector,
@@ -169,19 +197,11 @@ public class OutboundMatcher {
final Optional<String[]> moreAttrsToGet,
final Item... linkingItems) {
- Set<String> matgFromPropagationActions = new HashSet<>();
- resource.getPropagationActions().forEach(impl -> {
- try {
- matgFromPropagationActions.addAll(
- ImplementationManager.<PropagationActions>build(impl).
- moreAttrsToGet(Optional.empty(), provision));
- } catch (Exception e) {
- LOG.error("While building {}", impl, e);
- }
- });
+ Stream<String> matgFromPropagationActions = getPropagationActions(resource).stream().
+ flatMap(a -> a.moreAttrsToGet(Optional.empty(), provision).stream());
Optional<String[]> effectiveMATG = Optional.of(Stream.concat(
moreAttrsToGet.stream().flatMap(Stream::of),
- matgFromPropagationActions.stream()).toArray(String[]::new));
+ matgFromPropagationActions).toArray(String[]::new));
Optional<PushCorrelationRule> rule = rule(resource, provision);
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 8dd27604a2..f077b2c499 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
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
@@ -34,6 +35,7 @@ import org.apache.syncope.common.lib.to.OrgUnit;
import org.apache.syncope.common.lib.to.Provision;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
@@ -42,6 +44,7 @@ import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
import org.apache.syncope.core.persistence.api.entity.AnyType;
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.Implementation;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.task.PullTask;
@@ -87,11 +90,18 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
@Autowired
protected AnyUtilsFactory anyUtilsFactory;
+ @Autowired
+ protected PlainAttrValidationManager validator;
+
protected final Map<String, SyncToken> latestSyncTokens = new HashMap<>();
+ protected ProvisioningProfile<PullTask, PullActions> profile;
+
protected final Map<String, MutablePair<Integer, String>> handled = new HashMap<>();
- protected ProvisioningProfile<PullTask, PullActions> profile;
+ protected final Map<String, PullActions> perContextActions = new ConcurrentHashMap<>();
+
+ protected Optional<ReconFilterBuilder> perContextReconFilterBuilder = Optional.empty();
@Override
public void setLatestSyncToken(final String objectClass, final SyncToken latestSyncToken) {
@@ -165,22 +175,28 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
});
}
- protected List<PullActions> buildPullActions(final PullTask pullTask) {
- List<PullActions> actions = new ArrayList<>();
- pullTask.getActions().forEach(impl -> {
+ protected List<PullActions> getPullActions(final List<? extends Implementation> impls) {
+ List<PullActions> result = new ArrayList<>();
+
+ impls.forEach(impl -> {
try {
- actions.add(ImplementationManager.build(impl));
+ result.add(ImplementationManager.build(
+ impl,
+ () -> perContextActions.get(impl.getKey()),
+ instance -> perContextActions.put(impl.getKey(), instance)));
} catch (Exception e) {
LOG.warn("While building {}", impl, e);
}
});
- return actions;
- }
- protected ReconFilterBuilder buildReconFilterBuilder(final PullTask pullTask)
- throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ return result;
+ }
- return ImplementationManager.build(pullTask.getReconFilterBuilder());
+ protected ReconFilterBuilder getReconFilterBuilder(final PullTask pullTask) throws ClassNotFoundException {
+ return ImplementationManager.build(
+ pullTask.getReconFilterBuilder(),
+ () -> perContextReconFilterBuilder.orElse(null),
+ instance -> perContextReconFilterBuilder = Optional.of(instance));
}
protected RealmPullResultHandler buildRealmHandler() {
@@ -217,10 +233,8 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
LOG.debug("Executing pull on {}", pullTask.getResource());
- List<PullActions> actions = buildPullActions(pullTask);
-
profile = new ProvisioningProfile<>(connector, pullTask);
- profile.getActions().addAll(actions);
+ profile.getActions().addAll(getPullActions(pullTask.getActions()));
profile.setDryRun(dryRun);
profile.setConflictResolutionAction(pullTask.getResource().getPullPolicy() == null
? ConflictResolutionAction.IGNORE
@@ -230,7 +244,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
latestSyncTokens.clear();
if (!profile.isDryRun()) {
- for (PullActions action : actions) {
+ for (PullActions action : profile.getActions()) {
action.beforeAll(profile);
}
}
@@ -244,7 +258,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
OrgUnit orgUnit = pullTask.getResource().getOrgUnit();
Set<String> moreAttrsToGet = new HashSet<>();
- actions.forEach(action -> moreAttrsToGet.addAll(action.moreAttrsToGet(profile, orgUnit)));
+ profile.getActions().forEach(a -> moreAttrsToGet.addAll(a.moreAttrsToGet(profile, orgUnit)));
OperationOptions options = MappingUtils.buildOperationOptions(
MappingUtils.getPullItems(orgUnit.getItems().stream()), moreAttrsToGet.toArray(String[]::new));
@@ -274,9 +288,8 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
break;
case FILTERED_RECONCILIATION:
- connector.filteredReconciliation(
- new ObjectClass(orgUnit.getObjectClass()),
- buildReconFilterBuilder(pullTask),
+ connector.filteredReconciliation(new ObjectClass(orgUnit.getObjectClass()),
+ getReconFilterBuilder(pullTask),
handler,
options);
break;
@@ -295,14 +308,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
}
// ...then provisions for any types
- ProvisionSorter provisionSorter = new DefaultProvisionSorter();
- if (pullTask.getResource().getProvisionSorter() != null) {
- try {
- provisionSorter = ImplementationManager.build(pullTask.getResource().getProvisionSorter());
- } catch (Exception e) {
- LOG.error("While building {}", pullTask.getResource().getProvisionSorter(), e);
- }
- }
+ ProvisionSorter provisionSorter = getProvisionSorter(pullTask);
GroupPullResultHandler ghandler = buildGroupHandler();
for (Provision provision : pullTask.getResource().getProvisions().stream().
@@ -332,7 +338,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
try {
Set<String> moreAttrsToGet = new HashSet<>();
- actions.forEach(action -> moreAttrsToGet.addAll(action.moreAttrsToGet(profile, provision)));
+ profile.getActions().forEach(a -> moreAttrsToGet.addAll(a.moreAttrsToGet(profile, provision)));
Stream<Item> mapItems = Stream.concat(
MappingUtils.getPullItems(provision.getMapping().getItems().stream()),
virSchemaDAO.find(pullTask.getResource().getKey(), anyType.getKey()).stream().
@@ -362,9 +368,8 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
break;
case FILTERED_RECONCILIATION:
- connector.filteredReconciliation(
- new ObjectClass(provision.getObjectClass()),
- buildReconFilterBuilder(pullTask),
+ connector.filteredReconciliation(new ObjectClass(provision.getObjectClass()),
+ getReconFilterBuilder(pullTask),
handler,
options);
break;
@@ -385,7 +390,9 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
&& result.getOperation() == ResourceOperation.CREATE
&& result.getAnyType().equals(provision.getAnyType())).
forEach(result -> anyUtils.addAttr(
- result.getKey(), plainSchemaDAO.find(provision.getUidOnCreate()), result.getUidValue()));
+ validator,
+ result.getKey(),
+ plainSchemaDAO.find(provision.getUidOnCreate()), result.getUidValue()));
}
} catch (Throwable t) {
throw new JobExecutionException("While pulling from connector", t);
@@ -398,7 +405,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
}
if (!profile.isDryRun()) {
- for (PullActions action : actions) {
+ for (PullActions action : profile.getActions()) {
action.afterAll(profile);
}
}
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 b6dcf6932d..18305af5bd 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
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
@@ -38,6 +39,7 @@ import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+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.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.group.Group;
@@ -83,6 +85,8 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
protected final Map<String, MutablePair<Integer, String>> handled = new HashMap<>();
+ protected final Map<String, PushActions> perContextActions = new ConcurrentHashMap<>();
+
protected void reportHandled(final String anyType, final String key) {
MutablePair<Integer, String> pair = handled.get(anyType);
if (pair == null) {
@@ -151,6 +155,23 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
createBean(DefaultGroupPushResultHandler.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
}
+ protected List<PushActions> getPushActions(final List<? extends Implementation> impls) {
+ List<PushActions> result = new ArrayList<>();
+
+ impls.forEach(impl -> {
+ try {
+ result.add(ImplementationManager.build(
+ impl,
+ () -> perContextActions.get(impl.getKey()),
+ instance -> perContextActions.put(impl.getKey(), instance)));
+ } catch (Exception e) {
+ LOG.warn("While building {}", impl, e);
+ }
+ });
+
+ return result;
+ }
+
@Override
protected String doExecuteProvisioning(
final PushTask pushTask,
@@ -161,17 +182,8 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
LOG.debug("Executing push on {}", pushTask.getResource());
- List<PushActions> actions = new ArrayList<>();
- pushTask.getActions().forEach(impl -> {
- try {
- actions.add(ImplementationManager.build(impl));
- } catch (Exception e) {
- LOG.warn("While building {}", impl, e);
- }
- });
-
profile = new ProvisioningProfile<>(connector, pushTask);
- profile.getActions().addAll(actions);
+ profile.getActions().addAll(getPushActions(pushTask.getActions()));
profile.setDryRun(dryRun);
profile.setConflictResolutionAction(pushTask.getResource().getPushPolicy() == null
? ConflictResolutionAction.IGNORE
@@ -179,7 +191,7 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
profile.setExecutor(executor);
if (!profile.isDryRun()) {
- for (PushActions action : actions) {
+ for (PushActions action : profile.getActions()) {
action.beforeAll(profile);
}
}
@@ -208,14 +220,7 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
}
// ...then provisions for any types
- ProvisionSorter provisionSorter = new DefaultProvisionSorter();
- if (pushTask.getResource().getProvisionSorter() != null) {
- try {
- provisionSorter = ImplementationManager.build(pushTask.getResource().getProvisionSorter());
- } catch (Exception e) {
- LOG.error("While building {}", pushTask.getResource().getProvisionSorter(), e);
- }
- }
+ ProvisionSorter provisionSorter = getProvisionSorter(pushTask);
for (Provision provision : pushTask.getResource().getProvisions().stream().
filter(provision -> provision.getMapping() != null).sorted(provisionSorter).
@@ -269,7 +274,7 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
}
if (!profile.isDryRun() && !interrupt) {
- for (PushActions action : actions) {
+ for (PushActions action : profile.getActions()) {
action.afterAll(profile);
}
}
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
index 390dcbcd8d..a71163ec3d 100644
--- 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
@@ -18,10 +18,11 @@
*/
package org.apache.syncope.core.provisioning.java.pushpull;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.syncope.common.lib.to.Item;
import org.apache.syncope.common.lib.to.Provision;
@@ -29,7 +30,6 @@ import org.apache.syncope.common.lib.to.ProvisioningReport;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
-import org.apache.syncope.common.lib.types.IdMImplementationType;
import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.PullMode;
import org.apache.syncope.common.lib.types.UnmatchingRule;
@@ -37,7 +37,6 @@ import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
-import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.task.AnyTemplatePullTask;
import org.apache.syncope.core.persistence.api.entity.task.PullTask;
@@ -50,7 +49,6 @@ import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullResultHandle
import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePullExecutor;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
import org.apache.syncope.core.provisioning.java.utils.TemplateUtils;
-import org.apache.syncope.core.spring.ImplementationManager;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -75,20 +73,6 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
LOG.debug("Executing pull on {}", resource);
- List<PullActions> actions = new ArrayList<>();
- pullTaskTO.getActions().forEach(key -> {
- Implementation impl = implementationDAO.find(key);
- if (impl == null || !IdMImplementationType.PULL_ACTIONS.equals(impl.getType())) {
- 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 {
PullTask pullTask = entityFactory.newEntity(PullTask.class);
pullTask.setResource(resource);
@@ -125,10 +109,11 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
profile = new ProvisioningProfile<>(connector, pullTask);
profile.setDryRun(false);
profile.setConflictResolutionAction(ConflictResolutionAction.FIRSTMATCH);
- profile.getActions().addAll(actions);
+ profile.getActions().addAll(getPullActions(pullTaskTO.getActions().stream().
+ map(implementationDAO::find).filter(Objects::nonNull).collect(Collectors.toList())));
profile.setExecutor(executor);
- for (PullActions action : actions) {
+ for (PullActions action : profile.getActions()) {
action.beforeAll(profile);
}
@@ -154,7 +139,7 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
// execute filtered pull
Set<String> matg = new HashSet<>(moreAttrsToGet);
- actions.forEach(action -> matg.addAll(action.moreAttrsToGet(profile, provision)));
+ profile.getActions().forEach(a -> matg.addAll(a.moreAttrsToGet(profile, provision)));
Stream<Item> mapItems = Stream.concat(
MappingUtils.getPullItems(provision.getMapping().getItems().stream()),
@@ -173,7 +158,7 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
LOG.error("While setting group owners", e);
}
- for (PullActions action : actions) {
+ for (PullActions action : profile.getActions()) {
action.afterAll(profile);
}
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
index 6c8685ec59..9e67fce043 100644
--- 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
@@ -18,20 +18,19 @@
*/
package org.apache.syncope.core.provisioning.java.pushpull;
-import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
import org.apache.syncope.common.lib.to.Provision;
import org.apache.syncope.common.lib.to.ProvisioningReport;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
-import org.apache.syncope.common.lib.types.IdMImplementationType;
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.AnyType;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
-import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.task.PushTask;
import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
import org.apache.syncope.core.provisioning.api.Connector;
@@ -40,7 +39,6 @@ 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.provisioning.api.pushpull.UserPushResultHandler;
-import org.apache.syncope.core.spring.ImplementationManager;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -49,7 +47,7 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
@Autowired
protected ImplementationDAO implementationDAO;
- protected List<PushActions> before(
+ protected void before(
final ExternalResource resource,
final Connector connector,
final PushTaskTO pushTaskTO,
@@ -57,20 +55,6 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
LOG.debug("Executing push on {}", resource);
- List<PushActions> actions = new ArrayList<>();
- pushTaskTO.getActions().forEach(key -> {
- Implementation impl = implementationDAO.find(key);
- if (impl == null || !IdMImplementationType.PUSH_ACTIONS.equals(impl.getType())) {
- LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", key);
- } else {
- try {
- actions.add(ImplementationManager.build(impl));
- } catch (Exception e) {
- LOG.warn("While building {}", impl, e);
- }
- }
- });
-
PushTask pushTask = entityFactory.newEntity(PushTask.class);
pushTask.setResource(resource);
pushTask.setMatchingRule(pushTaskTO.getMatchingRule() == null
@@ -84,14 +68,13 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
profile = new ProvisioningProfile<>(connector, pushTask);
profile.setExecutor(executor);
- profile.getActions().addAll(actions);
+ profile.getActions().addAll(getPushActions(pushTaskTO.getActions().stream().
+ map(implementationDAO::find).filter(Objects::nonNull).collect(Collectors.toList())));
profile.setConflictResolutionAction(ConflictResolutionAction.FIRSTMATCH);
- for (PushActions action : actions) {
+ for (PushActions action : profile.getActions()) {
action.beforeAll(profile);
}
-
- return actions;
}
@Override
@@ -104,7 +87,7 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
final String executor) throws JobExecutionException {
try {
- List<PushActions> actions = before(resource, connector, pushTaskTO, executor);
+ before(resource, connector, pushTaskTO, executor);
AnyType anyType = anyTypeDAO.find(provision.getAnyType());
@@ -126,7 +109,7 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
doHandle(List.of(any), handler, resource);
- for (PushActions action : actions) {
+ for (PushActions action : profile.getActions()) {
action.afterAll(profile);
}
@@ -148,14 +131,14 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
final String executor) throws JobExecutionException {
try {
- List<PushActions> actions = before(resource, connector, pushTaskTO, executor);
+ before(resource, connector, pushTaskTO, executor);
UserPushResultHandler handler = buildUserHandler();
handler.setProfile(profile);
handler.handle(account, provision);
- for (PushActions action : actions) {
+ for (PushActions action : profile.getActions()) {
action.afterAll(profile);
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPullJobDelegate.java
index b7cb57ac50..4d39209061 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPullJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPullJobDelegate.java
@@ -18,10 +18,11 @@
*/
package org.apache.syncope.core.provisioning.java.pushpull.stream;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.syncope.common.lib.to.Item;
import org.apache.syncope.common.lib.to.Mapping;
@@ -52,7 +53,6 @@ import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullResultHandle
import org.apache.syncope.core.provisioning.api.pushpull.stream.SyncopeStreamPullExecutor;
import org.apache.syncope.core.provisioning.java.pushpull.PullJobDelegate;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
-import org.apache.syncope.core.spring.ImplementationManager;
import org.apache.syncope.core.spring.security.SecureRandomUtils;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.quartz.JobExecutionException;
@@ -168,20 +168,6 @@ public class StreamPullJobDelegate extends PullJobDelegate implements SyncopeStr
LOG.debug("Executing stream pull");
- List<PullActions> actions = new ArrayList<>();
- pullTaskTO.getActions().forEach(key -> {
- Implementation impl = implementationDAO.find(key);
- if (impl == null || !IdMImplementationType.PULL_ACTIONS.equals(impl.getType())) {
- 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 {
ExternalResource resource =
externalResource(anyType, keyColumn, columns, conflictResolutionAction, pullCorrelationRule);
@@ -202,9 +188,10 @@ public class StreamPullJobDelegate extends PullJobDelegate implements SyncopeStr
profile = new ProvisioningProfile<>(connector, pullTask);
profile.setDryRun(false);
profile.setConflictResolutionAction(conflictResolutionAction);
- profile.getActions().addAll(actions);
+ profile.getActions().addAll(getPullActions(pullTaskTO.getActions().stream().
+ map(implementationDAO::find).filter(Objects::nonNull).collect(Collectors.toList())));
- for (PullActions action : actions) {
+ for (PullActions action : profile.getActions()) {
action.beforeAll(profile);
}
@@ -228,7 +215,7 @@ public class StreamPullJobDelegate extends PullJobDelegate implements SyncopeStr
// execute filtered pull
Set<String> moreAttrsToGet = new HashSet<>();
- actions.forEach(action -> moreAttrsToGet.addAll(action.moreAttrsToGet(profile, provision)));
+ profile.getActions().forEach(a -> moreAttrsToGet.addAll(a.moreAttrsToGet(profile, provision)));
Stream<Item> mapItems = Stream.concat(
MappingUtils.getPullItems(provision.getMapping().getItems().stream()),
@@ -246,7 +233,7 @@ public class StreamPullJobDelegate extends PullJobDelegate implements SyncopeStr
LOG.error("While setting group owners", e);
}
- for (PullActions action : actions) {
+ for (PullActions action : profile.getActions()) {
action.afterAll(profile);
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPushJobDelegate.java
index 14bf80104f..7c9c765f85 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPushJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/stream/StreamPushJobDelegate.java
@@ -18,8 +18,9 @@
*/
package org.apache.syncope.core.provisioning.java.pushpull.stream;
-import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
import org.apache.syncope.common.lib.to.Item;
import org.apache.syncope.common.lib.to.Mapping;
import org.apache.syncope.common.lib.to.Provision;
@@ -44,7 +45,6 @@ import org.apache.syncope.core.provisioning.api.pushpull.UserPushResultHandler;
import org.apache.syncope.core.provisioning.api.pushpull.stream.SyncopeStreamPushExecutor;
import org.apache.syncope.core.provisioning.java.pushpull.PushJobDelegate;
import org.apache.syncope.core.spring.ApplicationContextProvider;
-import org.apache.syncope.core.spring.ImplementationManager;
import org.apache.syncope.core.spring.security.SecureRandomUtils;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -128,20 +128,6 @@ public class StreamPushJobDelegate extends PushJobDelegate implements SyncopeStr
LOG.debug("Executing stream push as {}", executor);
- List<PushActions> pushActions = new ArrayList<>();
- pushTaskTO.getActions().forEach(key -> {
- Implementation impl = implementationDAO.find(key);
- if (impl == null || !IdMImplementationType.PUSH_ACTIONS.equals(impl.getType())) {
- LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", key);
- } else {
- try {
- pushActions.add(ImplementationManager.build(impl));
- } catch (Exception e) {
- LOG.warn("While building {}", impl, e);
- }
- }
- });
-
try {
ExternalResource resource = externalResource(anyType, columns, propagationActions);
@@ -156,10 +142,11 @@ public class StreamPushJobDelegate extends PushJobDelegate implements SyncopeStr
profile = new ProvisioningProfile<>(connector, pushTask);
profile.setExecutor(executor);
- profile.getActions().addAll(pushActions);
+ profile.getActions().addAll(getPushActions(pushTaskTO.getActions().stream().
+ map(implementationDAO::find).filter(Objects::nonNull).collect(Collectors.toList())));
profile.setConflictResolutionAction(ConflictResolutionAction.FIRSTMATCH);
- for (PushActions action : pushActions) {
+ for (PushActions action : profile.getActions()) {
action.beforeAll(profile);
}
@@ -181,7 +168,7 @@ public class StreamPushJobDelegate extends PushJobDelegate implements SyncopeStr
doHandle(anys, handler, resource);
- for (PushActions action : pushActions) {
+ for (PushActions action : profile.getActions()) {
action.afterAll(profile);
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
index bf48dc0a2a..46d49cbfdd 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
@@ -21,8 +21,10 @@ package org.apache.syncope.core.provisioning.java.utils;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
@@ -49,6 +51,8 @@ public final class MappingUtils {
private static final Logger LOG = LoggerFactory.getLogger(MappingUtils.class);
+ private static final Map<String, ItemTransformer> PER_CONTEXT_ITEM_TRANSFORMERS = new ConcurrentHashMap<>();
+
public static Optional<Item> getConnObjectKeyItem(final Provision provision) {
Mapping mapping = null;
if (provision != null) {
@@ -91,7 +95,10 @@ public final class MappingUtils {
// Then other custom transformers
transformers.forEach(impl -> {
try {
- result.add(ImplementationManager.build(impl));
+ result.add(ImplementationManager.build(
+ impl,
+ () -> PER_CONTEXT_ITEM_TRANSFORMERS.get(impl.getKey()),
+ instance -> PER_CONTEXT_ITEM_TRANSFORMERS.put(impl.getKey(), instance)));
} catch (Exception e) {
LOG.error("While building {}", impl, e);
}
diff --git a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DefaultMappingManagerTest.java b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DefaultMappingManagerTest.java
index 86f038a4b4..e15ed0c937 100644
--- a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DefaultMappingManagerTest.java
+++ b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DefaultMappingManagerTest.java
@@ -30,6 +30,7 @@ import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.to.Provision;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.CipherAlgorithm;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
@@ -84,6 +85,9 @@ public class DefaultMappingManagerTest extends AbstractTest {
@Autowired
private EntityFactory entityFactory;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
@Test
public void prepareAttrsForUser() {
User bellini = userDAO.findByUsername("bellini");
@@ -251,7 +255,7 @@ public class DefaultMappingManagerTest extends AbstractTest {
UPlainAttr cool = entityFactory.newEntity(UPlainAttr.class);
cool.setOwner(user);
cool.setSchema(plainSchemaDAO.find("cool"));
- cool.add("true", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+ cool.add(validator, "true", anyUtilsFactory.getInstance(AnyTypeKind.USER));
user.add(cool);
user = userDAO.save(user);
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java b/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java
deleted file mode 100644
index 7b69fee180..0000000000
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * 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.spring;
-
-import groovy.lang.GroovyClassLoader;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import org.apache.syncope.common.lib.policy.AccountRuleConf;
-import org.apache.syncope.common.lib.policy.PasswordRuleConf;
-import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
-import org.apache.syncope.common.lib.policy.PushCorrelationRuleConf;
-import org.apache.syncope.common.lib.report.ReportletConf;
-import org.apache.syncope.core.persistence.api.ImplementationLookup;
-import org.apache.syncope.core.persistence.api.dao.AccountRule;
-import org.apache.syncope.core.persistence.api.dao.PasswordRule;
-import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
-import org.apache.syncope.core.persistence.api.dao.PushCorrelationRule;
-import org.apache.syncope.core.persistence.api.dao.Reportlet;
-import org.apache.syncope.core.persistence.api.entity.Implementation;
-import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
-import org.apache.syncope.core.spring.security.AuthContextUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.beans.factory.support.DefaultListableBeanFactory;
-
-public final class ImplementationManager {
-
- private static final Logger LOG = LoggerFactory.getLogger(ImplementationManager.class);
-
- private static final GroovyClassLoader GROOVY_CLASSLOADER = new GroovyClassLoader();
-
- private static final Map<String, Class<?>> CLASS_CACHE = Collections.synchronizedMap(new HashMap<>());
-
- public static Optional<Reportlet> buildReportlet(final Implementation impl)
- throws InstantiationException, IllegalAccessException {
-
- switch (impl.getEngine()) {
- case GROOVY:
- return Optional.of(ImplementationManager.<Reportlet>buildGroovy(impl));
-
- case JAVA:
- default:
- ReportletConf reportletConf = POJOHelper.deserialize(impl.getBody(), ReportletConf.class);
- Class<? extends Reportlet> reportletClass = ApplicationContextProvider.getApplicationContext().
- getBean(ImplementationLookup.class).getReportletClass(reportletConf.getClass());
-
- Reportlet reportlet = buildJavaWithConf(reportletClass);
- if (reportlet == null) {
- LOG.warn("Could not find matching reportlet for {}", reportletConf.getClass());
- } else {
- reportlet.setConf(reportletConf);
- }
-
- return Optional.ofNullable(reportlet);
- }
- }
-
- public static Optional<AccountRule> buildAccountRule(final Implementation impl)
- throws InstantiationException, IllegalAccessException {
-
- switch (impl.getEngine()) {
- case GROOVY:
- return Optional.of(ImplementationManager.<AccountRule>buildGroovy(impl));
-
- case JAVA:
- default:
- AccountRuleConf ruleConf = POJOHelper.deserialize(impl.getBody(), AccountRuleConf.class);
- Class<? extends AccountRule> ruleClass = ApplicationContextProvider.getApplicationContext().
- getBean(ImplementationLookup.class).getAccountRuleClass(ruleConf.getClass());
-
- AccountRule rule = buildJavaWithConf(ruleClass);
- if (rule == null) {
- LOG.warn("Could not find matching account rule for {}", impl.getClass());
- } else {
- rule.setConf(ruleConf);
- }
-
- return Optional.ofNullable(rule);
- }
- }
-
- public static Optional<PasswordRule> buildPasswordRule(final Implementation impl)
- throws InstantiationException, IllegalAccessException {
-
- switch (impl.getEngine()) {
- case GROOVY:
- return Optional.of(ImplementationManager.<PasswordRule>buildGroovy(impl));
-
- case JAVA:
- default:
- PasswordRuleConf ruleConf = POJOHelper.deserialize(impl.getBody(), PasswordRuleConf.class);
- Class<? extends PasswordRule> ruleClass = ApplicationContextProvider.getApplicationContext().
- getBean(ImplementationLookup.class).getPasswordRuleClass(ruleConf.getClass());
-
- PasswordRule rule = buildJavaWithConf(ruleClass);
- if (rule == null) {
- LOG.warn("Could not find matching password rule for {}", impl.getClass());
- } else {
- rule.setConf(ruleConf);
- }
-
- return Optional.ofNullable(rule);
- }
- }
-
- public static Optional<PullCorrelationRule> buildPullCorrelationRule(final Implementation impl)
- throws InstantiationException, IllegalAccessException {
-
- switch (impl.getEngine()) {
- case GROOVY:
- return Optional.of(ImplementationManager.<PullCorrelationRule>buildGroovy(impl));
-
- case JAVA:
- default:
- PullCorrelationRuleConf ruleConf =
- POJOHelper.deserialize(impl.getBody(), PullCorrelationRuleConf.class);
- Class<? extends PullCorrelationRule> ruleClass = ApplicationContextProvider.getApplicationContext().
- getBean(ImplementationLookup.class).getPullCorrelationRuleClass(ruleConf.getClass());
-
- PullCorrelationRule rule = buildJavaWithConf(ruleClass);
- if (rule == null) {
- LOG.warn("Could not find matching pull correlation rule for {}", impl.getClass());
- } else {
- rule.setConf(ruleConf);
- }
-
- return Optional.ofNullable(rule);
- }
- }
-
- public static Optional<PushCorrelationRule> buildPushCorrelationRule(final Implementation impl)
- throws InstantiationException, IllegalAccessException {
-
- switch (impl.getEngine()) {
- case GROOVY:
- return Optional.of(ImplementationManager.<PushCorrelationRule>buildGroovy(impl));
-
- case JAVA:
- default:
- PushCorrelationRuleConf ruleConf =
- POJOHelper.deserialize(impl.getBody(), PushCorrelationRuleConf.class);
- Class<? extends PushCorrelationRule> ruleClass = ApplicationContextProvider.getApplicationContext().
- getBean(ImplementationLookup.class).getPushCorrelationRuleClass(ruleConf.getClass());
-
- PushCorrelationRule rule = buildJavaWithConf(ruleClass);
- if (rule == null) {
- LOG.warn("Could not find matching push correlation rule for {}", impl.getClass());
- } else {
- rule.setConf(ruleConf);
- }
-
- return Optional.ofNullable(rule);
- }
- }
-
- public static <T> T build(final Implementation impl)
- throws InstantiationException, IllegalAccessException, ClassNotFoundException {
-
- switch (impl.getEngine()) {
- case GROOVY:
- return ImplementationManager.<T>buildGroovy(impl);
-
- case JAVA:
- default:
- return ImplementationManager.<T>buildJava(impl);
- }
- }
-
- @SuppressWarnings("unchecked")
- private static <T> T buildGroovy(final Implementation impl)
- throws InstantiationException, IllegalAccessException {
-
- Class<?> clazz;
- if (CLASS_CACHE.containsKey(impl.getKey())) {
- clazz = CLASS_CACHE.get(impl.getKey());
- } else {
- clazz = GROOVY_CLASSLOADER.parseClass(impl.getBody());
- CLASS_CACHE.put(impl.getKey(), clazz);
- }
-
- return (T) ApplicationContextProvider.getBeanFactory().
- createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> T buildJava(final Implementation impl)
- throws ClassNotFoundException {
-
- Class<?> clazz;
- if (CLASS_CACHE.containsKey(impl.getKey())) {
- clazz = CLASS_CACHE.get(impl.getKey());
- } else {
- clazz = Class.forName(impl.getBody());
- CLASS_CACHE.put(impl.getKey(), clazz);
- }
-
- return (T) ApplicationContextProvider.getBeanFactory().
- createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> T buildJavaWithConf(final Class<T> clazz) {
- if (clazz != null) {
- String domainableBeanNameWithConf = AuthContextUtils.getDomain() + clazz.getName();
- DefaultListableBeanFactory beanFactory = ApplicationContextProvider.getBeanFactory();
-
- if (beanFactory.containsSingleton(domainableBeanNameWithConf)) {
- return (T) beanFactory.getSingleton(domainableBeanNameWithConf);
- }
-
- synchronized (beanFactory.getSingletonMutex()) {
- if (beanFactory.containsSingleton(domainableBeanNameWithConf)) {
- return (T) beanFactory.getSingleton(domainableBeanNameWithConf);
- } else {
- T bean = (T) beanFactory.createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
- beanFactory.registerSingleton(domainableBeanNameWithConf, bean);
- return bean;
- }
- }
- }
- return null;
- }
-
- public static Class<?> purge(final String implementation) {
- return CLASS_CACHE.remove(implementation);
- }
-
- private ImplementationManager() {
- // private constructor for static utility class
- }
-}
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/implementation/ImplementationManager.java b/core/spring/src/main/java/org/apache/syncope/core/spring/implementation/ImplementationManager.java
new file mode 100644
index 0000000000..9ca5410ce5
--- /dev/null
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/implementation/ImplementationManager.java
@@ -0,0 +1,252 @@
+/*
+ * 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.spring;
+
+import groovy.lang.GroovyClassLoader;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.policy.AccountRuleConf;
+import org.apache.syncope.common.lib.policy.PasswordRuleConf;
+import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
+import org.apache.syncope.common.lib.policy.PushCorrelationRuleConf;
+import org.apache.syncope.common.lib.report.ReportletConf;
+import org.apache.syncope.core.persistence.api.ImplementationLookup;
+import org.apache.syncope.core.persistence.api.dao.AccountRule;
+import org.apache.syncope.core.persistence.api.dao.PasswordRule;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.PushCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.Reportlet;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.spring.implementation.InstanceScope;
+import org.apache.syncope.core.spring.implementation.SyncopeImplementation;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+
+public final class ImplementationManager {
+
+ private static final GroovyClassLoader GROOVY_CLASSLOADER = new GroovyClassLoader();
+
+ private static final Map<String, Class<?>> CLASS_CACHE = Collections.synchronizedMap(new HashMap<>());
+
+ public static Optional<Reportlet> buildReportlet(final Implementation impl) throws ClassNotFoundException {
+ switch (impl.getEngine()) {
+ case GROOVY:
+ return Optional.of(build(impl));
+
+ case JAVA:
+ default:
+ ReportletConf conf = POJOHelper.deserialize(impl.getBody(), ReportletConf.class);
+ Class<? extends Reportlet> clazz = ApplicationContextProvider.getApplicationContext().
+ getBean(ImplementationLookup.class).getReportletClass(conf.getClass());
+
+ if (clazz == null) {
+ return Optional.empty();
+ }
+
+ Reportlet reportlet = (Reportlet) ApplicationContextProvider.getBeanFactory().
+ createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ reportlet.setConf(conf);
+ return Optional.of(reportlet);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Optional<AccountRule> buildAccountRule(
+ final Implementation impl,
+ final Supplier<AccountRule> cacheGetter,
+ final Consumer<AccountRule> cachePutter)
+ throws ClassNotFoundException {
+
+ switch (impl.getEngine()) {
+ case GROOVY:
+ return Optional.of(build(impl, cacheGetter, cachePutter));
+
+ case JAVA:
+ default:
+ AccountRuleConf conf = POJOHelper.deserialize(impl.getBody(), AccountRuleConf.class);
+ Class<AccountRule> clazz = (Class<AccountRule>) ApplicationContextProvider.getApplicationContext().
+ getBean(ImplementationLookup.class).getAccountRuleClass(conf.getClass());
+
+ if (clazz == null) {
+ return Optional.empty();
+ }
+
+ AccountRule rule = build(clazz, true, cacheGetter, cachePutter);
+ rule.setConf(conf);
+ return Optional.of(rule);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Optional<PasswordRule> buildPasswordRule(
+ final Implementation impl,
+ final Supplier<PasswordRule> cacheGetter,
+ final Consumer<PasswordRule> cachePutter)
+ throws ClassNotFoundException {
+
+ switch (impl.getEngine()) {
+ case GROOVY:
+ return Optional.of(build(impl, cacheGetter, cachePutter));
+
+ case JAVA:
+ default:
+ PasswordRuleConf conf = POJOHelper.deserialize(impl.getBody(), PasswordRuleConf.class);
+ Class<PasswordRule> clazz = (Class<PasswordRule>) ApplicationContextProvider.getApplicationContext().
+ getBean(ImplementationLookup.class).getPasswordRuleClass(conf.getClass());
+
+ if (clazz == null) {
+ return Optional.empty();
+ }
+
+ PasswordRule rule = build(clazz, true, cacheGetter, cachePutter);
+ rule.setConf(conf);
+ return Optional.of(rule);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Optional<PullCorrelationRule> buildPullCorrelationRule(
+ final Implementation impl,
+ final Supplier<PullCorrelationRule> cacheGetter,
+ final Consumer<PullCorrelationRule> cachePutter)
+ throws ClassNotFoundException {
+
+ switch (impl.getEngine()) {
+ case GROOVY:
+ return Optional.of(build(impl, cacheGetter, cachePutter));
+
+ case JAVA:
+ default:
+ PullCorrelationRuleConf conf = POJOHelper.deserialize(impl.getBody(), PullCorrelationRuleConf.class);
+ Class<PullCorrelationRule> clazz =
+ (Class<PullCorrelationRule>) ApplicationContextProvider.getApplicationContext().
+ getBean(ImplementationLookup.class).getPullCorrelationRuleClass(conf.getClass());
+
+ if (clazz == null) {
+ return Optional.empty();
+ }
+
+ PullCorrelationRule rule = build(clazz, true, cacheGetter, cachePutter);
+ rule.setConf(conf);
+ return Optional.of(rule);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Optional<PushCorrelationRule> buildPushCorrelationRule(
+ final Implementation impl,
+ final Supplier<PushCorrelationRule> cacheGetter,
+ final Consumer<PushCorrelationRule> cachePutter)
+ throws ClassNotFoundException {
+
+ switch (impl.getEngine()) {
+ case GROOVY:
+ return Optional.of(build(impl, cacheGetter, cachePutter));
+
+ case JAVA:
+ default:
+ PushCorrelationRuleConf conf = POJOHelper.deserialize(impl.getBody(), PushCorrelationRuleConf.class);
+ Class<PushCorrelationRule> clazz =
+ (Class<PushCorrelationRule>) ApplicationContextProvider.getApplicationContext().
+ getBean(ImplementationLookup.class).getPushCorrelationRuleClass(conf.getClass());
+
+ if (clazz == null) {
+ return Optional.empty();
+ }
+
+ PushCorrelationRule rule = build(clazz, true, cacheGetter, cachePutter);
+ rule.setConf(conf);
+ return Optional.of(rule);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> Pair<Class<T>, Boolean> getClass(final Implementation impl) throws ClassNotFoundException {
+ if (CLASS_CACHE.containsKey(impl.getKey())) {
+ return Pair.of((Class<T>) CLASS_CACHE.get(impl.getKey()), true);
+ }
+
+ Class<?> clazz;
+ switch (impl.getEngine()) {
+ case GROOVY:
+ clazz = GROOVY_CLASSLOADER.parseClass(impl.getBody());
+ break;
+
+ case JAVA:
+ default:
+ clazz = Class.forName(impl.getBody());
+ }
+
+ CLASS_CACHE.put(impl.getKey(), clazz);
+ return Pair.of((Class<T>) clazz, false);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T build(final Implementation impl) throws ClassNotFoundException {
+ return (T) ApplicationContextProvider.getBeanFactory().
+ createBean(getClass(impl).getLeft(), AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T build(
+ final Class<T> clazz,
+ final boolean classCached,
+ final Supplier<T> cacheGetter,
+ final Consumer<T> cachePutter) {
+
+ boolean perContext = Optional.ofNullable(clazz.getAnnotation(SyncopeImplementation.class)).
+ map(ann -> ann.scope() == InstanceScope.PER_CONTEXT).
+ orElse(true);
+ T instance = null;
+ if (perContext && classCached) {
+ instance = cacheGetter.get();
+ }
+ if (instance == null) {
+ instance = (T) ApplicationContextProvider.getBeanFactory().
+ createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+
+ if (perContext) {
+ cachePutter.accept(instance);
+ }
+ }
+
+ return instance;
+ }
+
+ public static <T> T build(final Implementation impl, final Supplier<T> cacheGetter, final Consumer<T> cachePutter)
+ throws ClassNotFoundException {
+
+ Pair<Class<T>, Boolean> clazz = getClass(impl);
+
+ return build(clazz.getLeft(), clazz.getRight(), cacheGetter, cachePutter);
+ }
+
+ public static Class<?> purge(final String implementation) {
+ return CLASS_CACHE.remove(implementation);
+ }
+
+ private ImplementationManager() {
+ // private constructor for static utility class
+ }
+}
diff --git a/common/idm/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java b/core/spring/src/main/java/org/apache/syncope/core/spring/implementation/InstanceScope.java
similarity index 65%
copy from common/idm/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java
copy to core/spring/src/main/java/org/apache/syncope/core/spring/implementation/InstanceScope.java
index 1abf35f88a..fb76a83303 100644
--- a/common/idm/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/implementation/InstanceScope.java
@@ -16,18 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.common.lib.types;
+package org.apache.syncope.core.spring.implementation;
-/**
- * Enum of all possible capabilities that a connector instance can expose.
- */
-public enum ConnectorCapability {
-
- AUTHENTICATE,
- CREATE,
- UPDATE,
- DELETE,
- SEARCH,
- SYNC;
+public enum InstanceScope {
+ /**
+ * The declaring Implementation will be instantiated every time it is getting invoked.
+ */
+ PER_CALL,
+ /**
+ * The declaring Implementation will be instantiated once, by the time of first invocation; such instance will
+ * not be destroyed until the Spring Context gets refreshed or shut down.
+ */
+ PER_CONTEXT
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java b/core/spring/src/main/java/org/apache/syncope/core/spring/implementation/SyncopeImplementation.java
similarity index 69%
copy from core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java
copy to core/spring/src/main/java/org/apache/syncope/core/spring/implementation/SyncopeImplementation.java
index 4ae6eb5740..30e8ee750c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/implementation/SyncopeImplementation.java
@@ -16,25 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.core.persistence.jpa.validation.entity;
+package org.apache.syncope.core.spring.implementation;
-import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import javax.validation.Constraint;
-import javax.validation.Payload;
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
-@Constraint(validatedBy = PlainAttrValidator.class)
-@Documented
-public @interface PlainAttrCheck {
+public @interface SyncopeImplementation {
- String message() default "{org.apache.syncope.core.persistence.validation.attr}";
-
- Class<?>[] groups() default {};
-
- Class<? extends Payload>[] payload() default {};
+ InstanceScope scope() default InstanceScope.PER_CONTEXT;
}
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
index 3499bea17e..daa33514ef 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
@@ -20,9 +20,13 @@ package org.apache.syncope.core.spring.security;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
+import org.apache.syncope.core.persistence.api.dao.PasswordRule;
import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
import org.apache.syncope.core.spring.ImplementationManager;
import org.apache.syncope.core.spring.policy.DefaultPasswordRule;
@@ -48,6 +52,8 @@ public class DefaultPasswordGenerator implements PasswordGenerator {
protected static final int MIN_LENGTH_IF_ZERO = 8;
+ protected final Map<String, PasswordRule> perContextPasswordRules = new ConcurrentHashMap<>();
+
@Transactional(readOnly = true)
@Override
public String generate(final ExternalResource resource) {
@@ -60,21 +66,31 @@ public class DefaultPasswordGenerator implements PasswordGenerator {
return generate(policies);
}
- @Override
- public String generate(final List<PasswordPolicy> policies) {
- List<DefaultPasswordRuleConf> ruleConfs = new ArrayList<>();
+ protected List<PasswordRule> getPasswordRules(final PasswordPolicy policy) {
+ List<PasswordRule> result = new ArrayList<>();
- policies.stream().forEach(policy -> policy.getRules().forEach(impl -> {
+ for (Implementation impl : policy.getRules()) {
try {
- ImplementationManager.buildPasswordRule(impl).ifPresent(rule -> {
- if (rule.getConf() instanceof DefaultPasswordRuleConf) {
- ruleConfs.add((DefaultPasswordRuleConf) rule.getConf());
- }
- });
+ ImplementationManager.buildPasswordRule(
+ impl,
+ () -> perContextPasswordRules.get(impl.getKey()),
+ instance -> perContextPasswordRules.put(impl.getKey(), instance)).
+ ifPresent(result::add);
} catch (Exception e) {
- LOG.error("Invalid {}, ignoring...", impl, e);
+ LOG.warn("While building {}", impl, e);
}
- }));
+ }
+
+ return result;
+ }
+
+ @Override
+ public String generate(final List<PasswordPolicy> policies) {
+ List<DefaultPasswordRuleConf> ruleConfs = new ArrayList<>();
+
+ policies.stream().forEach(policy -> getPasswordRules(policy).stream().
+ filter(rule -> rule.getConf() instanceof DefaultPasswordRuleConf).
+ forEach(rule -> ruleConfs.add((DefaultPasswordRuleConf) rule.getConf())));
return generate(merge(ruleConfs));
}
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/ImplementationManagerTest.java b/core/spring/src/test/java/org/apache/syncope/core/spring/ImplementationManagerTest.java
index 7fe3fe99c5..3f3f0f8796 100644
--- a/core/spring/src/test/java/org/apache/syncope/core/spring/ImplementationManagerTest.java
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/ImplementationManagerTest.java
@@ -51,8 +51,8 @@ public class ImplementationManagerTest {
String body = POJOHelper.serialize(createBaseDefaultPasswordRuleConf());
assertTimeoutPreemptively(Duration.ofSeconds(30), () -> {
- TestImplementation implementation = new TestImplementation();
- implementation.setBody(body);
+ TestImplementation impl = new TestImplementation();
+ impl.setBody(body);
ReentrantLock lock = new ReentrantLock();
lock.lock();
AtomicInteger runningThreads = new AtomicInteger(0);
@@ -66,7 +66,11 @@ public class ImplementationManagerTest {
Thread.yield();
}
try {
- ImplementationManager.buildPasswordRule(implementation).orElseThrow();
+ ImplementationManager.buildPasswordRule(
+ impl,
+ () -> null,
+ instance -> {
+ }).orElseThrow();
} catch (Exception e) {
errorMessages.add(e.getLocalizedMessage());
errorCount.incrementAndGet();
diff --git a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/ElasticsearchPersistenceContext.java b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/ElasticsearchPersistenceContext.java
index 8fba443005..757fb34cee 100644
--- a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/ElasticsearchPersistenceContext.java
+++ b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/ElasticsearchPersistenceContext.java
@@ -19,6 +19,7 @@
package org.apache.syncope.core.persistence.jpa;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
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.DynRealmDAO;
@@ -56,6 +57,7 @@ public class ElasticsearchPersistenceContext {
final PlainSchemaDAO schemaDAO,
final EntityFactory entityFactory,
final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator,
final ElasticsearchClient client,
final @Lazy ElasticsearchUtils elasticsearchUtils) {
@@ -68,6 +70,7 @@ public class ElasticsearchPersistenceContext {
schemaDAO,
entityFactory,
anyUtilsFactory,
+ validator,
client,
elasticsearchUtils);
}
diff --git a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
index d203491980..d70d75ef30 100644
--- a/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
+++ b/ext/elasticsearch/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/ElasticsearchAnySearchDAO.java
@@ -48,6 +48,7 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.rest.api.service.JAXRSService;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
@@ -116,10 +117,21 @@ public class ElasticsearchAnySearchDAO extends AbstractAnySearchDAO {
final PlainSchemaDAO schemaDAO,
final EntityFactory entityFactory,
final AnyUtilsFactory anyUtilsFactory,
+ final PlainAttrValidationManager validator,
final ElasticsearchClient client,
final ElasticsearchUtils elasticsearchUtils) {
- super(realmDAO, dynRealmDAO, userDAO, groupDAO, anyObjectDAO, schemaDAO, entityFactory, anyUtilsFactory);
+ super(
+ realmDAO,
+ dynRealmDAO,
+ userDAO,
+ groupDAO,
+ anyObjectDAO,
+ schemaDAO,
+ entityFactory,
+ anyUtilsFactory,
+ validator);
+
this.client = client;
this.elasticsearchUtils = elasticsearchUtils;
}
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToDateItemTransformer.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToDateItemTransformer.java
index 894e03c36e..67ddf4d2df 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToDateItemTransformer.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToDateItemTransformer.java
@@ -25,7 +25,10 @@ import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
+import org.apache.syncope.core.spring.implementation.InstanceScope;
+import org.apache.syncope.core.spring.implementation.SyncopeImplementation;
+@SyncopeImplementation(scope = InstanceScope.PER_CONTEXT)
public class DateToDateItemTransformer implements ItemTransformer {
@Override
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToLongItemTransformer.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToLongItemTransformer.java
index 00a9152a34..03e135e703 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToLongItemTransformer.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToLongItemTransformer.java
@@ -25,7 +25,10 @@ import org.apache.syncope.common.lib.types.AttrSchemaType;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
+import org.apache.syncope.core.spring.implementation.InstanceScope;
+import org.apache.syncope.core.spring.implementation.SyncopeImplementation;
+@SyncopeImplementation(scope = InstanceScope.PER_CONTEXT)
public class DateToLongItemTransformer implements ItemTransformer {
@Override