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
The following commit(s) were added to refs/heads/2_1_X by this push: new 74b83cf21c [SYNCOPE-1704] Evicting JPAExternalResource instances from JPA cache when policies get updated 74b83cf21c is described below commit 74b83cf21c349b140193b2069a5a31bbdc2d77aa Author: Francesco Chicchiriccò <ilgro...@apache.org> AuthorDate: Wed Oct 26 16:36:46 2022 +0200 [SYNCOPE-1704] Evicting JPAExternalResource instances from JPA cache when policies get updated --- .../console/policies/PolicyModalPanelBuilder.java | 9 ++-- .../syncope/core/logic/ImplementationLogic.java | 4 ++ .../persistence/api/dao/ExternalResourceDAO.java | 3 +- .../jpa/dao/JPAExternalResourceDAO.java | 10 ++++ .../persistence/jpa/dao/JPAImplementationDAO.java | 14 +++++- .../core/persistence/jpa/dao/JPAPolicyDAO.java | 20 +++++++- .../jpa/entity/policy/JPAPropagationPolicy.java | 2 + .../jpa/entity/resource/JPAExternalResource.java | 2 +- .../core/persistence/jpa/outer/TaskTest.java | 57 ++++++++++------------ .../AbstractPropagationTaskExecutor.java | 14 +++--- 10 files changed, 88 insertions(+), 47 deletions(-) diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyModalPanelBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyModalPanelBuilder.java index e4497e450e..393bb9660a 100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyModalPanelBuilder.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyModalPanelBuilder.java @@ -140,7 +140,7 @@ public class PolicyModalPanelBuilder<T extends PolicyTO> extends AbstractModalPa this.policyTO = policyTO; - final List<Component> fields = new ArrayList<>(); + List<Component> fields = new ArrayList<>(); FieldPanel<String> description = new AjaxTextFieldPanel("field", "description", new PropertyModel<>(policyTO, "description"), false); @@ -148,7 +148,7 @@ public class PolicyModalPanelBuilder<T extends PolicyTO> extends AbstractModalPa fields.add(description); if (policyTO instanceof AccountPolicyTO) { - fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().build( + fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build( "field", "maxAuthenticationAttempts", Integer.class, @@ -165,7 +165,7 @@ public class PolicyModalPanelBuilder<T extends PolicyTO> extends AbstractModalPa new PropertyModel<>(policyTO, "passthroughResources"), new ListModel<>(resources.getObject()))); } else if (policyTO instanceof PasswordPolicyTO) { - fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().build( + fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build( "field", "historyLength", Integer.class, @@ -177,7 +177,7 @@ public class PolicyModalPanelBuilder<T extends PolicyTO> extends AbstractModalPa new PropertyModel<>(policyTO, "allowNullPassword"), false)); } else if (policyTO instanceof PropagationPolicyTO) { - fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().build( + fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build( "field", "maxAttempts", Integer.class, @@ -247,7 +247,6 @@ public class PolicyModalPanelBuilder<T extends PolicyTO> extends AbstractModalPa protected void populateItem(final ListItem<Component> item) { item.add(item.getModelObject()); } - }); } diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ImplementationLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ImplementationLogic.java index 19efd1f41d..7d82319acc 100644 --- a/core/logic/src/main/java/org/apache/syncope/core/logic/ImplementationLogic.java +++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ImplementationLogic.java @@ -176,6 +176,10 @@ public class ImplementationLogic extends AbstractTransactionalLogic<Implementati inUse = !realmDAO.findByLogicActions(implementation).isEmpty(); break; + case PROVISION_SORTER: + inUse = !resourceDAO.findByProvisionSorter(implementation).isEmpty(); + break; + case PROPAGATION_ACTIONS: inUse = !resourceDAO.findByPropagationActions(implementation).isEmpty(); break; diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java index ecde5f10b5..18815e134c 100644 --- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java +++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java @@ -38,6 +38,8 @@ public interface ExternalResourceDAO extends DAO<ExternalResource> { List<MappingItem> findByTransformer(Implementation transformer); + List<ExternalResource> findByProvisionSorter(Implementation provisionSorter); + List<ExternalResource> findByPropagationActions(Implementation propagationActions); List<ExternalResource> findByPolicy(Policy policy); @@ -49,5 +51,4 @@ public interface ExternalResourceDAO extends DAO<ExternalResource> { void deleteMapping(String schemaName); void delete(String key); - } diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java index 9512483407..6d8c4f7cf0 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java @@ -149,6 +149,16 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource> implem return query.getResultList(); } + @Override + public List<ExternalResource> findByProvisionSorter(final Implementation provisionSorter) { + TypedQuery<ExternalResource> query = entityManager().createQuery( + "SELECT e FROM " + JPAExternalResource.class.getSimpleName() + " e " + + "WHERE e.provisionSorter=:provisionSorter", ExternalResource.class); + query.setParameter("provisionSorter", provisionSorter); + + return query.getResultList(); + } + private StringBuilder getByPolicyQuery(final Class<? extends Policy> policyClass) { StringBuilder query = new StringBuilder("SELECT e FROM "). append(JPAExternalResource.class.getSimpleName()). 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 2a690ac569..56a9761e7c 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 @@ -21,16 +21,26 @@ package org.apache.syncope.core.persistence.jpa.dao; import java.util.List; import javax.persistence.TypedQuery; import org.apache.syncope.common.lib.types.ImplementationType; +import org.apache.syncope.core.persistence.api.dao.EntityCacheDAO; +import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO; 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.persistence.jpa.entity.resource.JPAExternalResource; import org.apache.syncope.core.spring.implementation.ImplementationManager; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @Repository public class JPAImplementationDAO extends AbstractDAO<Implementation> implements ImplementationDAO { + @Autowired + private ExternalResourceDAO resourceDAO; + + @Autowired + private EntityCacheDAO entityCacheDAO; + @Transactional(readOnly = true) @Override public Implementation find(final String key) { @@ -59,6 +69,9 @@ public class JPAImplementationDAO extends AbstractDAO<Implementation> implements ImplementationManager.purge(merged.getKey()); + resourceDAO.findByProvisionSorter(merged). + forEach(resource -> entityCacheDAO.evict(JPAExternalResource.class, resource.getKey())); + return merged; } @@ -72,5 +85,4 @@ public class JPAImplementationDAO extends AbstractDAO<Implementation> implements entityManager().remove(implementation); ImplementationManager.purge(key); } - } diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPolicyDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPolicyDAO.java index bcfee405d9..470f02644e 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPolicyDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPolicyDAO.java @@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.jpa.dao; import java.util.List; import javax.persistence.TypedQuery; +import org.apache.syncope.core.persistence.api.dao.EntityCacheDAO; import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO; import org.apache.syncope.core.persistence.api.dao.PolicyDAO; import org.apache.syncope.core.persistence.api.dao.RealmDAO; @@ -39,6 +40,7 @@ import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPropagationPolic import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPullPolicy; import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPushCorrelationRuleEntity; import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPushPolicy; +import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Repository; @@ -54,6 +56,10 @@ public class JPAPolicyDAO extends AbstractDAO<Policy> implements PolicyDAO { @Lazy private ExternalResourceDAO resourceDAO; + @Autowired + @Lazy + private EntityCacheDAO entityCacheDAO; + private <T extends Policy> Class<? extends AbstractPolicy> getEntityReference(final Class<T> reference) { return AccountPolicy.class.isAssignableFrom(reference) ? JPAAccountPolicy.class @@ -141,7 +147,19 @@ public class JPAPolicyDAO extends AbstractDAO<Policy> implements PolicyDAO { @Override public <T extends Policy> T save(final T policy) { - return entityManager().merge(policy); + T merged = entityManager().merge(policy); + + if (policy instanceof AccountPolicy + || policy instanceof PasswordPolicy + || policy instanceof PropagationPolicy + || policy instanceof PullPolicy + || policy instanceof PushPolicy) { + + resourceDAO.findByPolicy(policy). + forEach(resource -> entityCacheDAO.evict(JPAExternalResource.class, resource.getKey())); + } + + return merged; } @Override diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPropagationPolicy.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPropagationPolicy.java index 207886f382..048a88f6a5 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPropagationPolicy.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPropagationPolicy.java @@ -23,6 +23,7 @@ import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.Table; +import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import org.apache.syncope.common.lib.types.BackOffStrategy; import org.apache.syncope.core.persistence.api.entity.policy.PropagationPolicy; @@ -41,6 +42,7 @@ public class JPAPropagationPolicy extends AbstractPolicy implements PropagationP private String backOffParams; + @Min(1) @NotNull private Integer maxAttempts = 3; diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java index 14edc8f5c7..b85644f187 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java @@ -143,7 +143,7 @@ public class JPAExternalResource extends AbstractProvidedKeyEntity implements Ex @ManyToOne(fetch = FetchType.EAGER) private JPAPushPolicy pushPolicy; - @ManyToOne + @ManyToOne(fetch = FetchType.EAGER) private JPAImplementation provisionSorter; /** diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java index 67857462e7..f18255511e 100644 --- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java +++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java @@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.util.ArrayList; import java.util.Collections; @@ -31,7 +32,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; -import org.apache.syncope.common.lib.to.UserTO; import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.syncope.common.lib.types.ImplementationEngine; import org.apache.syncope.common.lib.types.ImplementationType; @@ -44,6 +44,7 @@ import org.apache.syncope.common.lib.types.UnmatchingRule; import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException; import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO; 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.dao.TaskDAO; import org.apache.syncope.core.persistence.api.dao.TaskExecDAO; import org.apache.syncope.core.persistence.api.dao.UserDAO; @@ -61,7 +62,6 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.apache.syncope.core.persistence.api.entity.task.PullTask; -import org.apache.syncope.core.persistence.api.entity.task.AnyTemplatePullTask; import org.apache.syncope.core.provisioning.api.pushpull.PullActions; @Transactional("Master") @@ -79,6 +79,9 @@ public class TaskTest extends AbstractTest { @Autowired private UserDAO userDAO; + @Autowired + private RealmDAO realmDAO; + @Autowired private ImplementationDAO implementationDAO; @@ -108,7 +111,7 @@ public class TaskTest extends AbstractTest { } @Test - public void save() { + public void savePropagationTask() { ExternalResource resource = resourceDAO.find("ws-target-resource-1"); assertNotNull(resource); @@ -135,9 +138,8 @@ public class TaskTest extends AbstractTest { entityManager().flush(); - resource = resourceDAO.find("ws-target-resource-1"); assertTrue(taskDAO.findAll( - TaskType.PROPAGATION, resource, null, null, null, -1, -1, Collections.<OrderByClause>emptyList()). + TaskType.PROPAGATION, resource, null, null, null, -1, -1, Collections.emptyList()). contains(task)); } @@ -236,51 +238,45 @@ public class TaskTest extends AbstractTest { @Test public void savePullTask() { - ExternalResource resource = resourceDAO.find("ws-target-resource-1"); - assertNotNull(resource); - - AnyTemplatePullTask template = entityFactory.newEntity(AnyTemplatePullTask.class); - template.set(new UserTO()); - PullTask task = entityFactory.newEntity(PullTask.class); task.setName("savePullTask"); task.setDescription("PullTask description"); task.setActive(true); task.setPullMode(PullMode.FULL_RECONCILIATION); - task.add(template); + task.setJobDelegate(implementationDAO.find("PullJobDelegate")); + task.setDestinationRealm(realmDAO.getRoot()); task.setCronExpression("BLA BLA"); task.setMatchingRule(MatchingRule.UPDATE); task.setUnmatchingRule(UnmatchingRule.PROVISION); + // now adding PullActions + Implementation pullActions = entityFactory.newEntity(Implementation.class); + pullActions.setKey("PullActions" + UUID.randomUUID().toString()); + pullActions.setEngine(ImplementationEngine.JAVA); + pullActions.setType(ImplementationType.PULL_ACTIONS); + pullActions.setBody(PullActions.class.getName()); + pullActions = implementationDAO.save(pullActions); + entityManager().flush(); + + task.add(pullActions); + // this save() fails because of an invalid Cron Expression - InvalidEntityException exception = null; try { taskDAO.save(task); + fail(); } catch (InvalidEntityException e) { - exception = e; + assertNotNull(e); } - assertNotNull(exception); - task.setCronExpression(null); + // this save() fails because a PullTask requires a target resource - exception = null; try { taskDAO.save(task); + fail(); } catch (InvalidEntityException e) { - exception = e; + assertNotNull(e); } - assertNotNull(exception); - - task.setResource(resource); - - Implementation pullActions = entityFactory.newEntity(Implementation.class); - pullActions.setKey("PullActions" + UUID.randomUUID().toString()); - pullActions.setEngine(ImplementationEngine.JAVA); - pullActions.setType(ImplementationType.PULL_ACTIONS); - pullActions.setBody(PullActions.class.getName()); - pullActions = implementationDAO.save(pullActions); - - task.add(pullActions); + task.setResource(resourceDAO.find("ws-target-resource-1")); // this save() finally works task = taskDAO.save(task); @@ -329,5 +325,4 @@ public class TaskTest extends AbstractTest { assertEquals("issueSYNCOPE144_2", actual.getName()); assertEquals("issueSYNCOPE144 Description_2", actual.getDescription()); } - } 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 78dbfe3714..beab6387a8 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 @@ -347,21 +347,21 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask ExponentialBackOffPolicy eBackOffPolicy = new ExponentialBackOffPolicy(); if (params.length > 0) { try { - eBackOffPolicy.setInitialInterval(Long.valueOf(params[0])); + eBackOffPolicy.setInitialInterval(Long.parseLong(params[0])); } catch (NumberFormatException e) { LOG.error("Could not convert to long: {}", params[0], e); } } if (params.length > 1) { try { - eBackOffPolicy.setMaxInterval(Long.valueOf(params[1])); + eBackOffPolicy.setMaxInterval(Long.parseLong(params[1])); } catch (NumberFormatException e) { LOG.error("Could not convert to long: {}", params[1], e); } } if (params.length > 2) { try { - eBackOffPolicy.setMultiplier(Double.valueOf(params[2])); + eBackOffPolicy.setMultiplier(Double.parseDouble(params[2])); } catch (NumberFormatException e) { LOG.error("Could not convert to double: {}", params[2], e); } @@ -373,21 +373,21 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask ExponentialRandomBackOffPolicy erBackOffPolicy = new ExponentialRandomBackOffPolicy(); if (params.length > 0) { try { - erBackOffPolicy.setInitialInterval(Long.valueOf(params[0])); + erBackOffPolicy.setInitialInterval(Long.parseLong(params[0])); } catch (NumberFormatException e) { LOG.error("Could not convert to long: {}", params[0], e); } } if (params.length > 1) { try { - erBackOffPolicy.setMaxInterval(Long.valueOf(params[1])); + erBackOffPolicy.setMaxInterval(Long.parseLong(params[1])); } catch (NumberFormatException e) { LOG.error("Could not convert to long: {}", params[1], e); } } if (params.length > 2) { try { - erBackOffPolicy.setMultiplier(Double.valueOf(params[2])); + erBackOffPolicy.setMultiplier(Double.parseDouble(params[2])); } catch (NumberFormatException e) { LOG.error("Could not convert to double: {}", params[2], e); } @@ -400,7 +400,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask FixedBackOffPolicy fBackOffPolicy = new FixedBackOffPolicy(); if (params.length > 0) { try { - fBackOffPolicy.setBackOffPeriod(Long.valueOf(params[0])); + fBackOffPolicy.setBackOffPeriod(Long.parseLong(params[0])); } catch (NumberFormatException e) { LOG.error("Could not convert to long: {}", params[0], e); }