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 13:53:25 UTC
[syncope] 02/02: [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 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 89a3251b12ec5fea5facd058cc0ab26e3b492cff
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 | 17 +-
.../init/ClassPathScanImplementationLookup.java | 6 +-
...idator.java => PlainAttrValidationManager.java} | 6 +-
...Validator.java => PlainAttrValueValidator.java} | 6 +-
.../core/persistence/api/entity/AnyUtils.java | 3 +-
.../core/persistence/api/entity/PlainAttr.java | 6 +-
.../entity/JPAJSONAttributableValidator.java | 2 +-
.../attrvalue/validation/AbstractValidator.java | 17 +-
.../attrvalue/validation/AlwaysTrueValidator.java | 3 +-
.../jpa/attrvalue/validation/BasicValidator.java | 5 +-
.../jpa/attrvalue/validation/BinaryValidator.java | 3 +-
.../DefaultPlainAttrValidationManager.java | 62 +++++
.../validation/EmailAddressValidator.java | 3 +-
.../jpa/attrvalue/validation/URLValidator.java | 3 +-
.../persistence/jpa/dao/AbstractAnySearchDAO.java | 9 +-
.../core/persistence/jpa/dao/JPAAnyMatchDAO.java | 21 +-
.../persistence/jpa/dao/JPAImplementationDAO.java | 2 +-
.../core/persistence/jpa/dao/JPAUserDAO.java | 73 ++++--
.../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/ConfTest.java | 6 +-
.../core/persistence/jpa/inner/PlainAttrTest.java | 24 +-
.../core/persistence/jpa/outer/AnySearchTest.java | 8 +-
.../core/persistence/jpa/outer/ConfTest.java | 6 +-
.../core/persistence/jpa/outer/GroupTest.java | 12 +-
.../core/persistence/jpa/outer/RoleTest.java | 6 +-
.../core/persistence/jpa/outer/UserTest.java | 16 +-
.../java/data/AbstractAnyDataBinder.java | 6 +-
.../java/data/ConfigurationDataBinderImpl.java | 8 +-
.../java/data/ImplementationDataBinderImpl.java | 4 +-
.../java/data/ResourceDataBinderImpl.java | 10 +-
.../core/provisioning/java/job/TaskJob.java | 2 +-
.../java/job/report/DefaultReportJobDelegate.java | 2 +-
.../notification/DefaultNotificationManager.java | 11 +-
.../AbstractPropagationTaskExecutor.java | 12 +-
.../java/propagation/AzurePropagationActions.java | 3 +
.../propagation/DBPasswordPropagationActions.java | 3 +
.../propagation/GoogleAppsPropagationActions.java | 3 +
.../LDAPMembershipPropagationActions.java | 3 +
.../LDAPPasswordPropagationActions.java | 3 +
.../pushpull/AbstractProvisioningJobDelegate.java | 24 ++
.../provisioning/java/pushpull/InboundMatcher.java | 39 +++-
.../java/pushpull/OutboundMatcher.java | 49 ++--
.../java/pushpull/PullJobDelegate.java | 64 +++---
.../java/pushpull/PushJobDelegate.java | 55 ++---
.../java/pushpull/SinglePullJobDelegate.java | 29 +--
.../java/pushpull/SinglePushJobDelegate.java | 37 +--
.../pushpull/stream/StreamPullJobDelegate.java | 33 +--
.../pushpull/stream/StreamPushJobDelegate.java | 25 +-
.../core/provisioning/java/utils/MappingUtils.java | 11 +-
.../provisioning/java/MappingManagerImplTest.java | 4 +
.../syncope/core/spring/ImplementationManager.java | 251 ---------------------
.../implementation/ImplementationManager.java | 251 +++++++++++++++++++++
.../core/spring/implementation/InstanceScope.java | 26 +--
.../implementation/SyncopeImplementation.java} | 16 +-
.../spring/security/DefaultPasswordGenerator.java | 42 ++--
.../core/spring/ImplementationManagerTest.java | 13 +-
.../core/reference/DateToDateItemTransformer.java | 3 +
.../core/reference/DateToLongItemTransformer.java | 3 +
63 files changed, 802 insertions(+), 620 deletions(-)
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java
index 41b1e4a27f..bd3b11f22f 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ConnectorCapability.java
@@ -29,6 +29,7 @@ public enum ConnectorCapability {
AUTHENTICATE,
CREATE,
UPDATE,
+ UPDATE_DELTA,
DELETE,
SEARCH,
SYNC;
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
index 5e73e52a2c..154090479d 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
+++ b/core/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.patch.AnyPatch;
@@ -37,7 +39,7 @@ import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.provisioning.api.LogicActions;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class AbstractAnyLogic<TO extends AnyTO, P extends AnyPatch> extends AbstractResourceAssociator<TO> {
@@ -51,18 +53,23 @@ public abstract class AbstractAnyLogic<TO extends AnyTO, P extends AnyPatch> ext
@Autowired
private TemplateUtils templateUtils;
- private List<LogicActions> getActions(final Realm realm) {
- List<LogicActions> actions = new ArrayList<>();
+ protected final Map<String, LogicActions> perContextActions = new ConcurrentHashMap<>();
+
+ protected List<LogicActions> getActions(final Realm realm) {
+ 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;
}
protected Pair<TO, List<LogicActions>> beforeCreate(final TO input) {
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
index f206b15394..9053ae5357 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
@@ -34,7 +34,7 @@ import org.apache.syncope.common.lib.types.ImplementationType;
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;
@@ -134,7 +134,7 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
scanner.addIncludeFilter(new AssignableTypeFilter(PropagationActions.class));
scanner.addIncludeFilter(new AssignableTypeFilter(PullActions.class));
scanner.addIncludeFilter(new AssignableTypeFilter(PushActions.class));
- scanner.addIncludeFilter(new AssignableTypeFilter(Validator.class));
+ scanner.addIncludeFilter(new AssignableTypeFilter(PlainAttrValueValidator.class));
scanner.addIncludeFilter(new AssignableTypeFilter(RecipientsProvider.class));
scanner.addIncludeFilter(new AssignableTypeFilter(AuditAppender.class));
scanner.addIncludeFilter(new AssignableTypeFilter(ProvisionSorter.class));
@@ -234,7 +234,7 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
classNames.get(ImplementationType.PUSH_ACTIONS).add(bd.getBeanClassName());
}
- if (Validator.class.isAssignableFrom(clazz) && !isAbstractClazz) {
+ if (PlainAttrValueValidator.class.isAssignableFrom(clazz) && !isAbstractClazz) {
classNames.get(ImplementationType.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 90b3c96ff0..b2ea89cf49 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
@@ -23,6 +23,7 @@ import java.util.Set;
import org.apache.syncope.common.lib.patch.AnyPatch;
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;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
@@ -56,5 +57,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/validation/entity/JPAJSONAttributableValidator.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/JPAJSONAttributableValidator.java
index b8d1a08ceb..8b09663d22 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/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 fc64f03f30..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 b32f91c684..2fa44704c8 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..6f7bfd2833
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/DefaultPlainAttrValidationManager.java
@@ -0,0 +1,62 @@
+/*
+ * 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.implementation.ImplementationManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+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 1ee4126a33..6998ffbd22 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
@@ -36,6 +36,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;
@@ -61,7 +62,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.beans.factory.annotation.Autowired;
public abstract class AbstractAnySearchDAO extends AbstractDAO<Any<?>> implements AnySearchDAO {
@@ -96,6 +96,9 @@ public abstract class AbstractAnySearchDAO extends AbstractDAO<Any<?>> implement
@Autowired
protected AnyUtilsFactory anyUtilsFactory;
+ @Autowired
+ protected PlainAttrValidationManager validator;
+
protected SearchCond buildEffectiveCond(
final SearchCond cond,
final Set<String> dynRealmKeys,
@@ -190,7 +193,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());
@@ -252,7 +255,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 a1255d6376..c2458d4449 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.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
@@ -90,6 +91,9 @@ public class JPAAnyMatchDAO extends AbstractDAO<Any<?>> implements AnyMatchDAO {
@Autowired
private AnyUtilsFactory anyUtilsFactory;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
/**
* Verify if any matches the given search condition.
*
@@ -164,14 +168,11 @@ public class JPAAnyMatchDAO extends AbstractDAO<Any<?>> implements AnyMatchDAO {
}
if (match == null) {
- Optional<AnyCond> anyCond = cond.getLeaf(AnyCond.class);
- if (anyCond.isPresent()) {
- match = matches(any, anyCond.get(), not);
- } else {
- match = cond.getLeaf(AttrCond.class).
- map(leaf -> matches(any, leaf, not)).
- orElse(null);
- }
+ match = cond.getLeaf(AnyCond.class).
+ map(value -> matches(any, value, not)).
+ orElseGet(() -> cond.getLeaf(AttrCond.class).
+ map(leaf -> matches(any, leaf, not)).
+ orElse(null));
}
if (match == null) {
@@ -371,7 +372,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);
@@ -463,7 +464,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/JPAImplementationDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAImplementationDAO.java
index 9148fbb7cf..2a690ac569 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAImplementationDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAImplementationDAO.java
@@ -24,7 +24,7 @@ import org.apache.syncope.common.lib.types.ImplementationType;
import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.jpa.entity.JPAImplementation;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
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 ce2168bcbb..2ca5f2553b 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.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.persistence.NoResultException;
@@ -43,8 +44,10 @@ import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
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.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.PasswordRule;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.dao.RoleDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -69,7 +72,7 @@ import org.apache.syncope.core.persistence.jpa.entity.user.JPALinkedAccount;
import org.apache.syncope.core.persistence.jpa.entity.user.JPAUMembership;
import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.apache.syncope.core.spring.security.Encryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
@@ -100,6 +103,10 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
@Resource(name = "anonymousUser")
protected String anonymousUser;
+ protected final Map<String, AccountRule> perContextAccountRules = new ConcurrentHashMap<>();
+
+ protected final Map<String, PasswordRule> perContextPasswordRules = new ConcurrentHashMap<>();
+
@Override
protected AnyUtils init() {
return anyUtilsFactory.getInstance(AnyTypeKind.USER);
@@ -311,6 +318,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) {
@@ -326,15 +369,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(account -> rule.enforce(account));
- });
- }
+ user.getLinkedAccounts().stream().
+ filter(account -> account.getPassword() != null).
+ forEach(rule::enforce);
+ });
boolean matching = false;
if (policy.getHistoryLength() > 0) {
@@ -406,15 +447,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(account -> rule.enforce(account));
- });
- }
+ 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 7bdcc552c5..734c24dd84 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
@@ -27,6 +27,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;
@@ -67,11 +68,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);
@@ -84,7 +85,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;
@@ -95,7 +96,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 6c3e7da74e..55ea7884bd 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
@@ -37,6 +37,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;
@@ -391,7 +392,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<>();
@@ -410,7 +416,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 e26f5e93eb..88c8f42523 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.ImplementationType;
-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 2613a2290e..8565a7c2eb 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
@@ -29,7 +29,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/ConfTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConfTest.java
index 55f0b6b511..d6887a89c5 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConfTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConfTest.java
@@ -27,6 +27,7 @@ import java.util.Optional;
import org.apache.syncope.common.lib.types.AttrSchemaType;
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.ConfDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
@@ -49,6 +50,9 @@ public class ConfTest extends AbstractTest {
@Autowired
private PlainSchemaDAO plainSchemaDAO;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
@Test
public void read() {
Optional<? extends CPlainAttr> conf = confDAO.find("selfRegistration.allowed");
@@ -71,7 +75,7 @@ public class ConfTest extends AbstractTest {
} else {
attrValue = entityFactory.newEntity(CPlainAttrValue.class);
}
- newAttr.add(value, attrValue);
+ newAttr.add(validator, value, attrValue);
}
@Test
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 6059bd0989..bc297d6290 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
@@ -37,6 +37,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;
@@ -68,6 +69,9 @@ public class PlainAttrTest extends AbstractTest {
@Autowired
private AnyTypeClassDAO anyTypeClassDAO;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
@Tag("plainAttrTable")
@Test
public void findByKey() {
@@ -99,15 +103,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;
}
@@ -131,13 +135,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 {
@@ -226,7 +230,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);
@@ -256,7 +260,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());
@@ -275,8 +279,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());
@@ -303,7 +307,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 0f92bca3a8..13295200b0 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
@@ -31,6 +31,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.StandardEntitlement;
+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.RealmDAO;
import org.apache.syncope.core.persistence.api.dao.RoleDAO;
@@ -75,6 +76,9 @@ public class AnySearchTest extends AbstractTest {
@Autowired
private PlainSchemaDAO plainSchemaDAO;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
@Test
public void searchByDynMembership() {
// 1. create role with dynamic membership
@@ -201,14 +205,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/ConfTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
index fefa7ff4b5..48c2cbf91f 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.persistence.jpa.outer;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.ConfDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
@@ -42,6 +43,9 @@ public class ConfTest extends AbstractTest {
@Autowired
private PlainSchemaDAO plainSchemaDAO;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
private void add(final CPlainAttr newAttr, final String value) {
PlainAttrValue attrValue;
if (newAttr.getSchema().isUniqueConstraint()) {
@@ -50,7 +54,7 @@ public class ConfTest extends AbstractTest {
} else {
attrValue = entityFactory.newEntity(CPlainAttrValue.class);
}
- newAttr.add(value, attrValue);
+ newAttr.add(validator, value, attrValue);
}
@Test
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 646714278c..8c3b510ae5 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, () -> {
@@ -202,7 +206,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);
@@ -303,7 +307,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);
@@ -381,14 +385,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 709ef48c91..d43bfe7a77 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
@@ -33,6 +33,7 @@ import java.util.List;
import javax.persistence.Query;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.StandardEntitlement;
+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;
@@ -72,6 +73,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
@@ -107,7 +111,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 7f58bfc300..4e436ead63 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
@@ -33,6 +33,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;
@@ -97,6 +98,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"));
@@ -174,7 +178,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'
@@ -188,7 +192,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 {
@@ -209,7 +213,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'
@@ -222,7 +226,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);
@@ -264,7 +268,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();
@@ -404,7 +408,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);
userDAO.save(user);
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 07bb31f01b..ac105d65e3 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
@@ -45,6 +45,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;
@@ -150,6 +151,9 @@ abstract class AbstractAnyDataBinder {
@Autowired
protected OutboundMatcher outboundMatcher;
+ @Autowired
+ protected PlainAttrValidationManager validator;
+
protected void setRealm(final Any<?> any, final AnyPatch anyPatch) {
if (anyPatch.getRealm() != null && StringUtils.isNotBlank(anyPatch.getRealm().getValue())) {
Realm newRealm = realmDAO.findByFullPath(anyPatch.getRealm().getValue());
@@ -234,7 +238,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/ConfigurationDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
index 416cc9c0ad..e3bc95bbe1 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
@@ -18,7 +18,6 @@
*/
package org.apache.syncope.core.provisioning.java.data;
-import org.apache.syncope.core.provisioning.api.data.ConfigurationDataBinder;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@@ -29,6 +28,7 @@ import org.apache.syncope.common.lib.to.AttrTO;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.core.provisioning.api.jexl.JexlUtils;
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.ConfDAO;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
@@ -37,6 +37,7 @@ import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrUniqueValue;
import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrValue;
+import org.apache.syncope.core.provisioning.api.data.ConfigurationDataBinder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -46,6 +47,9 @@ public class ConfigurationDataBinderImpl extends AbstractAnyDataBinder implement
@Autowired
private ConfDAO confDAO;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
@Override
public List<AttrTO> getConfTO() {
return confDAO.get().getPlainAttrs().stream().map(attr -> getAttrTO(attr)).collect(Collectors.toList());
@@ -99,7 +103,7 @@ public class ConfigurationDataBinderImpl extends AbstractAnyDataBinder implement
attrValue = entityFactory.newEntity(CPlainAttrValue.class);
}
- attr.add(value, attrValue);
+ attr.add(validator, value, attrValue);
} catch (InvalidPlainAttrValueException e) {
LOG.warn("Invalid value for attribute " + schema.getKey() + ": " + value, e);
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 57b97e6ce3..a561be8f18 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
@@ -27,7 +27,7 @@ import org.apache.syncope.common.lib.to.ImplementationTO;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.ImplementationEngine;
import org.apache.syncope.common.lib.types.ImplementationType;
-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.Reportlet;
@@ -137,7 +137,7 @@ public class ImplementationDataBinderImpl implements ImplementationDataBinder {
break;
case VALIDATOR:
- base = Validator.class;
+ base = PlainAttrValueValidator.class;
break;
case 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 dd7773d654..27662bcf77 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
@@ -349,10 +349,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())) {
@@ -360,13 +360,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/job/TaskJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
index 962edc40d3..61fb5f530f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
@@ -27,7 +27,7 @@ import org.apache.syncope.core.provisioning.api.job.SchedTaskJobDelegate;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.apache.syncope.core.provisioning.api.job.JobManager;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/DefaultReportJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/DefaultReportJobDelegate.java
index e4050b7ea2..d25bbdc76c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/DefaultReportJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/DefaultReportJobDelegate.java
@@ -43,8 +43,8 @@ import org.apache.syncope.core.persistence.api.dao.Reportlet;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
import org.apache.syncope.core.persistence.api.entity.Report;
import org.apache.syncope.core.persistence.api.entity.ReportExec;
-import org.apache.syncope.core.spring.ImplementationManager;
import org.apache.syncope.core.provisioning.api.job.report.ReportJobDelegate;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 99dbde36b4..eb33975302 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
@@ -77,7 +77,7 @@ import org.apache.syncope.core.provisioning.api.notification.NotificationManager
import org.apache.syncope.core.provisioning.api.notification.RecipientsProvider;
import org.apache.syncope.core.provisioning.api.IntAttrNameParser;
import org.apache.syncope.core.provisioning.api.jexl.JexlUtils;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -163,6 +163,8 @@ public class DefaultNotificationManager implements NotificationManager {
@Autowired
private SearchCondVisitor searchCondVisitor;
+ private Optional<RecipientsProvider> perContextRecipientsProvider = Optional.empty();
+
@Transactional(readOnly = true)
@Override
public long getMaxRetries() {
@@ -218,8 +220,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 f0845383b5..78dbfe3714 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
@@ -38,6 +38,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.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.TaskDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -67,7 +68,7 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import org.apache.syncope.core.provisioning.java.pushpull.OutboundMatcher;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.identityconnectors.framework.common.objects.Attribute;
@@ -165,6 +166,9 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
@Autowired
protected OutboundMatcher outboundMatcher;
+ @Autowired
+ protected PlainAttrValidationManager validator;
+
@Override
public void expireRetryTemplate(final String resource) {
retryTemplates.remove(resource);
@@ -223,8 +227,10 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
task.getResource().getProvision(task.getAnyType()).ifPresent(provision -> {
if (provision.getUidOnCreate() != null) {
- anyUtilsFactory.getInstance(task.getAnyTypeKind()).
- addAttr(task.getEntityKey(), provision.getUidOnCreate(), result.getUidValue());
+ anyUtilsFactory.getInstance(task.getAnyTypeKind()).addAttr(validator,
+ task.getEntityKey(),
+ provision.getUidOnCreate(),
+ result.getUidValue());
}
});
} else {
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 2eeac67d67..b03e5ed42e 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
@@ -23,6 +23,8 @@ import java.util.Set;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
+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.ConnectorObject;
@@ -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 {
private 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 a40d9b29cd..bd187e82ea 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.task.PropagationTask;
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.PropagationTaskExecutor;
+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;
@@ -44,6 +46,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 {
private static final String CLEARTEXT = "CLEARTEXT";
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 68f0b66519..63316a6ea4 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
@@ -24,6 +24,8 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
+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.ConnectorObject;
@@ -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 {
private 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 5ff46c7e70..c382798357 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
@@ -40,6 +40,8 @@ import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.provisioning.api.DerAttrHandler;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
import org.identityconnectors.framework.common.objects.Attribute;
+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.AttributeUtil;
import org.identityconnectors.framework.common.objects.ConnectorObject;
@@ -54,6 +56,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 21e5e0c5e4..3549a72504 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.task.PropagationTask;
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.PropagationTaskExecutor;
+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;
@@ -44,6 +46,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/pushpull/AbstractProvisioningJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractProvisioningJobDelegate.java
index fb83490d44..7721c0e1b8 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
@@ -24,6 +24,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Objects;
import javax.annotation.Resource;
+import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.TraceLevel;
@@ -38,8 +39,11 @@ 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.ConnectorFactory;
import org.apache.syncope.common.lib.to.ProvisioningReport;
+import org.apache.syncope.core.provisioning.api.ProvisionSorter;
+import org.apache.syncope.core.provisioning.java.DefaultProvisionSorter;
import org.apache.syncope.core.provisioning.java.job.AbstractSchedTaskJobDelegate;
import org.apache.syncope.core.provisioning.java.job.TaskJob;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -110,6 +114,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.isPresent()) {
+ perContextProvisionSorter = Optional.of(new DefaultProvisionSorter());
+ }
+ return perContextProvisionSorter.get();
+ }
+
/**
* Create a textual report of the provisionig 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 a0d4cc8d14..1ff7827874 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
@@ -22,7 +22,9 @@ import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
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.types.AnyTypeKind;
@@ -52,6 +54,7 @@ import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
@@ -60,7 +63,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.Item;
import org.apache.syncope.core.provisioning.api.VirAttrHandler;
import org.apache.syncope.core.provisioning.api.IntAttrNameParser;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.identityconnectors.framework.common.objects.ConnectorObject;
@@ -113,6 +116,8 @@ public class InboundMatcher {
@Autowired
private AnyUtilsFactory anyUtilsFactory;
+ private final Map<String, PullCorrelationRule> perContextPullCorrelationRules = new ConcurrentHashMap<>();
+
public Optional<PullMatch> match(
final AnyType anyType,
final String nameValue,
@@ -339,27 +344,37 @@ public class InboundMatcher {
return result;
}
- /**
- * Finds internal entities based on external attributes and mapping.
- *
- * @param syncDelta change operation, including external attributes
- * @param provision mapping
- * @return list of matching users' / groups' / any objects' keys
- */
- public List<PullMatch> match(final SyncDelta syncDelta, final Provision provision) {
+ protected Optional<PullCorrelationRule> rule(final Provision provision) {
Optional<? extends PullCorrelationRuleEntity> correlationRule = provision.getResource().getPullPolicy() == null
? Optional.empty()
: provision.getResource().getPullPolicy().getCorrelationRule(provision.getAnyType());
Optional<PullCorrelationRule> rule = Optional.empty();
if (correlationRule.isPresent()) {
+ Implementation impl = correlationRule.get().getImplementation();
try {
- rule = ImplementationManager.buildPullCorrelationRule(correlationRule.get().getImplementation());
+ rule = ImplementationManager.buildPullCorrelationRule(
+ impl,
+ () -> perContextPullCorrelationRules.get(impl.getKey()),
+ instance -> perContextPullCorrelationRules.put(impl.getKey(), instance));
} catch (Exception e) {
- LOG.error("While building {}", correlationRule.get().getImplementation(), e);
+ LOG.error("While building {}", impl, e);
}
}
+ return rule;
+ }
+
+ /**
+ * Finds internal entities based on external attributes and mapping.
+ *
+ * @param syncDelta change operation, including external attributes
+ * @param provision mapping
+ * @return list of matching users' / groups' / any objects' keys
+ */
+ public List<PullMatch> match(final SyncDelta syncDelta, final Provision provision) {
+ Optional<PullCorrelationRule> rule = rule(provision);
+
List<PullMatch> result = Collections.emptyList();
try {
if (rule.isPresent()) {
@@ -442,7 +457,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 1add31108f..9851cfd92f 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
@@ -23,8 +23,10 @@ import java.util.Arrays;
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.types.AnyTypeKind;
@@ -33,9 +35,11 @@ import org.apache.syncope.core.persistence.api.dao.UserDAO;
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.Implementation;
import org.apache.syncope.core.persistence.api.entity.LinkingMappingItem;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.policy.PushCorrelationRuleEntity;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
@@ -45,7 +49,7 @@ import org.apache.syncope.core.provisioning.api.TimeoutException;
import org.apache.syncope.core.provisioning.api.VirAttrHandler;
import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
import org.identityconnectors.framework.common.objects.ConnectorObject;
import org.identityconnectors.framework.common.objects.SearchResult;
@@ -77,6 +81,10 @@ public class OutboundMatcher {
@Autowired
private VirAttrHandler virAttrHandler;
+ private final Map<String, PropagationActions> perContextActions = new ConcurrentHashMap<>();
+
+ private final Map<String, PushCorrelationRule> perContextPushCorrelationRules = new ConcurrentHashMap<>();
+
private Optional<PushCorrelationRule> rule(final Provision provision) {
Optional<? extends PushCorrelationRuleEntity> correlationRule = provision.getResource().getPushPolicy() == null
? Optional.empty()
@@ -84,10 +92,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);
}
}
@@ -149,6 +161,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,
@@ -157,19 +186,11 @@ public class OutboundMatcher {
final Optional<String[]> moreAttrsToGet,
final LinkingMappingItem... linkingItems) {
- Set<String> matgFromPropagationActions = new HashSet<>();
- provision.getResource().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(provision.getResource()).stream().
+ flatMap(a -> a.moreAttrsToGet(Optional.empty(), provision).stream());
Optional<String[]> effectiveMATG = Optional.of(Stream.concat(
moreAttrsToGet.map(Stream::of).orElse(Stream.empty()),
- matgFromPropagationActions.stream()).toArray(String[]::new));
+ matgFromPropagationActions).toArray(String[]::new));
Optional<PushCorrelationRule> rule = rule(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 19444449e7..116d89b954 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;
@@ -32,12 +33,14 @@ import org.apache.syncope.common.lib.types.ConflictResolutionAction;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.core.spring.ApplicationContextProvider;
+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.PullMatch;
import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
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.resource.Item;
@@ -64,8 +67,7 @@ import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.SyncToken;
import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
-import org.apache.syncope.core.provisioning.java.DefaultProvisionSorter;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.quartz.JobExecutionContext;
public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> implements SyncopePullExecutor {
@@ -82,10 +84,17 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
@Autowired
protected AnyUtilsFactory anyUtilsFactory;
+ @Autowired
+ protected PlainAttrValidationManager validator;
+
protected final Map<ObjectClass, SyncToken> latestSyncTokens = new HashMap<>();
protected final Map<ObjectClass, MutablePair<Integer, String>> handled = new HashMap<>();
+ protected final Map<String, PullActions> perContextActions = new ConcurrentHashMap<>();
+
+ protected Optional<ReconFilterBuilder> perContextReconFilterBuilder = Optional.empty();
+
protected ProvisioningProfile<PullTask, PullActions> profile;
@Override
@@ -162,22 +171,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() {
@@ -213,10 +228,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
@@ -225,7 +238,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);
}
}
@@ -239,7 +252,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(new String[0]));
@@ -269,7 +282,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
case FILTERED_RECONCILIATION:
connector.filteredReconciliation(
orgUnit.getObjectClass(),
- buildReconFilterBuilder(pullTask),
+ getReconFilterBuilder(pullTask),
handler,
options);
break;
@@ -287,14 +300,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().
@@ -322,7 +328,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<? extends Item> mapItems = Stream.concat(
MappingUtils.getPullItems(provision.getMapping().getItems().stream()),
virSchemaDAO.findByProvision(provision).stream().map(VirSchema::asLinkingMappingItem));
@@ -350,7 +356,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
case FILTERED_RECONCILIATION:
connector.filteredReconciliation(
provision.getObjectClass(),
- buildReconFilterBuilder(pullTask),
+ getReconFilterBuilder(pullTask),
handler,
options);
break;
@@ -371,7 +377,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
&& result.getOperation() == ResourceOperation.CREATE
&& result.getAnyType().equals(provision.getAnyType().getKey())).
forEach(result -> anyUtils.addAttr(
- result.getKey(), provision.getUidOnCreate(), result.getUidValue()));
+ validator, result.getKey(), provision.getUidOnCreate(), result.getUidValue()));
}
} catch (Throwable t) {
throw new JobExecutionException("While pulling from connector", t);
@@ -385,7 +391,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 55eee2e478..243eaf0827 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,20 +24,19 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
-import org.apache.syncope.core.persistence.api.search.SearchCondConverter;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.apache.syncope.core.persistence.api.dao.AnyDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
-import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.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;
@@ -46,6 +45,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.persistence.api.entity.task.PushTask;
import org.apache.syncope.core.persistence.api.entity.task.PushTaskAnyFilter;
import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.api.search.SearchCondConverter;
import org.apache.syncope.core.persistence.api.search.SearchCondVisitor;
import org.apache.syncope.core.provisioning.api.Connector;
import org.apache.syncope.core.provisioning.api.ProvisionSorter;
@@ -56,8 +56,8 @@ import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
import org.apache.syncope.core.provisioning.api.pushpull.RealmPushResultHandler;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopePushResultHandler;
import org.apache.syncope.core.provisioning.api.pushpull.UserPushResultHandler;
-import org.apache.syncope.core.provisioning.java.DefaultProvisionSorter;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -84,6 +84,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) {
@@ -154,6 +156,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,
@@ -163,24 +182,15 @@ 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
: pushTask.getResource().getPushPolicy().getConflictResolutionAction());
if (!profile.isDryRun()) {
- for (PushActions action : actions) {
+ for (PushActions action : profile.getActions()) {
action.beforeAll(profile);
}
}
@@ -209,14 +219,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).
@@ -259,14 +262,14 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
cond,
page,
AnyDAO.DEFAULT_PAGE_SIZE,
- Collections.<OrderByClause>emptyList(),
+ Collections.emptyList(),
provision.getAnyType().getKind());
doHandle(anys, handler, pushTask.getResource());
}
}
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 9f5066efdb..6a70e79177 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,21 +18,20 @@
*/
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.PullTaskTO;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
-import org.apache.syncope.common.lib.types.ImplementationType;
import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.PullMode;
import org.apache.syncope.common.lib.types.UnmatchingRule;
import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
-import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.resource.Item;
@@ -49,7 +48,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.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -74,20 +72,6 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
LOG.debug("Executing pull on {}", provision.getResource());
- List<PullActions> actions = new ArrayList<>();
- pullTaskTO.getActions().forEach(key -> {
- Implementation impl = implementationDAO.find(key);
- if (impl == null || impl.getType() != ImplementationType.PULL_ACTIONS) {
- LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", key);
- } else {
- try {
- actions.add(ImplementationManager.build(impl));
- } catch (Exception e) {
- LOG.warn("While building {}", impl, e);
- }
- }
- });
-
try {
PullTask pullTask = entityFactory.newEntity(PullTask.class);
pullTask.setResource(provision.getResource());
@@ -124,9 +108,10 @@ 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())));
- for (PullActions action : actions) {
+ for (PullActions action : profile.getActions()) {
action.beforeAll(profile);
}
@@ -150,7 +135,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<? extends Item> mapItems = Stream.concat(
MappingUtils.getPullItems(provision.getMapping().getItems().stream()),
@@ -168,7 +153,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 e6a4520b45..0cbf65aee1 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,17 +18,16 @@
*/
package org.apache.syncope.core.provisioning.java.pushpull;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
-import org.apache.syncope.common.lib.types.ImplementationType;
import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.UnmatchingRule;
import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.persistence.api.entity.task.PushTask;
import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
@@ -39,7 +38,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;
@@ -48,27 +46,13 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
@Autowired
private ImplementationDAO implementationDAO;
- private List<PushActions> before(
+ private void before(
final Provision provision,
final Connector connector,
final PushTaskTO pushTaskTO) throws JobExecutionException {
LOG.debug("Executing push on {}", provision.getResource());
- List<PushActions> actions = new ArrayList<>();
- pushTaskTO.getActions().forEach(key -> {
- Implementation impl = implementationDAO.find(key);
- if (impl == null || impl.getType() != ImplementationType.PUSH_ACTIONS) {
- LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", key);
- } else {
- try {
- actions.add(ImplementationManager.build(impl));
- } catch (Exception e) {
- LOG.warn("While building {}", impl, e);
- }
- }
- });
-
PushTask pushTask = entityFactory.newEntity(PushTask.class);
pushTask.setResource(provision.getResource());
pushTask.setMatchingRule(pushTaskTO.getMatchingRule() == null
@@ -81,14 +65,13 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
pushTask.setSyncStatus(pushTaskTO.isSyncStatus());
profile = new ProvisioningProfile<>(connector, pushTask);
- 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
@@ -99,7 +82,7 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
final PushTaskTO pushTaskTO) throws JobExecutionException {
try {
- List<PushActions> actions = before(provision, connector, pushTaskTO);
+ before(provision, connector, pushTaskTO);
SyncopePushResultHandler handler;
switch (provision.getAnyType().getKind()) {
@@ -119,7 +102,7 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
doHandle(Collections.singletonList(any), handler, provision.getResource());
- for (PushActions action : actions) {
+ for (PushActions action : profile.getActions()) {
action.afterAll(profile);
}
@@ -139,14 +122,14 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
final PushTaskTO pushTaskTO) throws JobExecutionException {
try {
- List<PushActions> actions = before(provision, connector, pushTaskTO);
+ before(provision, connector, pushTaskTO);
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 e0185b36e8..711856ae0c 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.PullTaskTO;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
@@ -35,7 +36,6 @@ 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.Implementation;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
-import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.policy.PullCorrelationRuleEntity;
import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
@@ -45,12 +45,12 @@ import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.persistence.api.entity.task.PullTask;
import org.apache.syncope.core.provisioning.api.pushpull.GroupPullResultHandler;
-import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
import org.apache.syncope.common.lib.to.ProvisioningReport;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullResultHandler;
-import org.apache.syncope.core.spring.ImplementationManager;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.apache.syncope.core.provisioning.api.pushpull.stream.SyncopeStreamPullExecutor;
@@ -169,20 +169,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 || impl.getType() != ImplementationType.PULL_ACTIONS) {
- LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", key);
- } else {
- try {
- actions.add(ImplementationManager.build(impl));
- } catch (Exception e) {
- LOG.warn("While building {}", impl, e);
- }
- }
- });
-
try {
ExternalResource resource =
externalResource(anyType, keyColumn, columns, conflictResolutionAction, pullCorrelationRule);
@@ -203,9 +189,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);
}
@@ -229,9 +216,9 @@ 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<? extends Item> mapItems = Stream.concat(
+ Stream<Item> mapItems = Stream.concat(
MappingUtils.getPullItems(provision.getMapping().getItems().stream()),
virSchemaDAO.findByProvision(provision).stream().map(VirSchema::asLinkingMappingItem));
@@ -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 18800a7792..417d7b3bce 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.ProvisioningReport;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
@@ -44,7 +45,6 @@ import org.apache.syncope.core.provisioning.api.pushpull.stream.SyncopeStreamPus
import org.apache.syncope.core.provisioning.api.pushpull.UserPushResultHandler;
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.identityconnectors.framework.common.objects.ObjectClass;
import org.quartz.JobExecutionException;
@@ -130,20 +130,6 @@ public class StreamPushJobDelegate extends PushJobDelegate implements SyncopeStr
LOG.debug("Executing stream push");
- List<PushActions> pushActions = new ArrayList<>();
- pushTaskTO.getActions().forEach(key -> {
- Implementation impl = implementationDAO.find(key);
- if (impl == null || impl.getType() != ImplementationType.PUSH_ACTIONS) {
- LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", key);
- } else {
- try {
- pushActions.add(ImplementationManager.build(impl));
- } catch (Exception e) {
- LOG.warn("While building {}", impl, e);
- }
- }
- });
-
try {
ExternalResource resource = externalResource(anyType, columns, propagationActions);
Provision provision = resource.getProvisions().get(0);
@@ -158,10 +144,11 @@ public class StreamPushJobDelegate extends PushJobDelegate implements SyncopeStr
pushTask.setSyncStatus(false);
profile = new ProvisioningProfile<>(connector, pushTask);
- 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);
}
@@ -183,7 +170,7 @@ public class StreamPushJobDelegate extends PushJobDelegate implements SyncopeStr
doHandle(anys, handler, provision.getResource());
- 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 1f5258506b..b3d771800a 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
@@ -22,8 +22,10 @@ import java.util.ArrayList;
import java.util.Arrays;
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;
@@ -44,12 +46,14 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
import org.apache.syncope.core.provisioning.api.data.JEXLItemTransformer;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
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<? extends MappingItem> getConnObjectKeyItem(final Provision provision) {
Mapping mapping = null;
if (provision != null) {
@@ -89,7 +93,10 @@ public final class MappingUtils {
// Then other custom transformers
item.getTransformers().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/MappingManagerImplTest.java b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/MappingManagerImplTest.java
index 527ace7297..188673d3d4 100644
--- a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/MappingManagerImplTest.java
+++ b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/MappingManagerImplTest.java
@@ -27,6 +27,7 @@ import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
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.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
@@ -59,6 +60,9 @@ public class MappingManagerImplTest extends AbstractTest {
@Autowired
private EntityFactory entityFactory;
+ @Autowired
+ private PlainAttrValidationManager validator;
+
@Test
public void prepareAttrsForUser() {
User bellini = userDAO.findByUsername("bellini");
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 6b637d8993..0000000000
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java
+++ /dev/null
@@ -1,251 +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 java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import groovy.lang.GroovyClassLoader;
-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..e00da5d9df
--- /dev/null
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/implementation/ImplementationManager.java
@@ -0,0 +1,251 @@
+/*
+ * 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.implementation;
+
+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.ApplicationContextProvider;
+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/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/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 41b1e4a27f..fb76a83303 100644
--- a/common/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,21 +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;
-import javax.xml.bind.annotation.XmlEnum;
-
-/**
- * Enum of all possible capabilities that a connector instance can expose.
- */
-@XmlEnum
-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 2613a2290e..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,26 +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 {
-
- String message() default "{org.apache.syncope.core.persistence.validation.attr}";
-
- Class<?>[] groups() default {};
+public @interface SyncopeImplementation {
- 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 037fac779b..58b1afec89 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,11 +20,15 @@ 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 org.apache.commons.lang3.StringUtils;
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.Implementation;
import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
-import org.apache.syncope.core.spring.ImplementationManager;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.apache.syncope.core.spring.policy.InvalidPasswordRuleConf;
import org.apache.syncope.core.spring.policy.PolicyPattern;
import org.slf4j.Logger;
@@ -47,6 +51,8 @@ public class DefaultPasswordGenerator implements PasswordGenerator {
private 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) throws InvalidPasswordRuleConf {
@@ -59,23 +65,33 @@ public class DefaultPasswordGenerator implements PasswordGenerator {
return generate(policies);
}
- @Override
- public String generate(final List<PasswordPolicy> policies) throws InvalidPasswordRuleConf {
- List<DefaultPasswordRuleConf> defaultRuleConfs = 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) {
- defaultRuleConfs.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) throws InvalidPasswordRuleConf {
+ 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())));
- DefaultPasswordRuleConf ruleConf = merge(defaultRuleConfs);
+ DefaultPasswordRuleConf ruleConf = merge(ruleConfs);
check(ruleConf);
return generate(ruleConf);
}
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 42b2d84b56..8258cb7274 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
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.core.spring;
+package org.apache.syncope.core.spring.implementation;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -66,8 +66,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);
@@ -81,8 +81,11 @@ public class ImplementationManagerTest {
Thread.yield();
}
try {
- ImplementationManager.buildPasswordRule(implementation).
- orElseThrow(() -> new IllegalStateException("No implementation returned"));
+ ImplementationManager.buildPasswordRule(
+ impl,
+ () -> null,
+ instance -> {
+ }).orElseThrow(() -> new IllegalStateException("No implementation returned"));
} catch (Exception e) {
errorMessages.add(e.getLocalizedMessage());
errorCount.incrementAndGet();
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 7e4f042bcd..6c304e83f1 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
@@ -26,7 +26,10 @@ 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.resource.Item;
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 a54bb05daa..c6ae4410d0 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.core.persistence.api.entity.Entity;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.resource.Item;
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