diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java index 329d8e51813..c8603728f9b 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java @@ -14,6 +14,8 @@ import javax.servlet.ServletContext; import javax.xml.datatype.Duration; +import com.evolveum.midpoint.repo.api.CacheRegistry; +import com.evolveum.midpoint.web.security.util.SecurityUtils; import org.apache.commons.configuration2.Configuration; import org.apache.wicket.*; import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior; diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index 22f9ca81bf1..f1c700a8031 100755 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd @@ -2105,7 +2105,7 @@ - + diff --git a/model/model-common/pom.xml b/model/model-common/pom.xml index 6dfb3e1e285..aa930f57610 100644 --- a/model/model-common/pom.xml +++ b/model/model-common/pom.xml @@ -80,11 +80,6 @@ repo-api 4.2-SNAPSHOT - - com.evolveum.midpoint.repo - repo-cache - 4.2-SNAPSHOT - com.evolveum.midpoint.repo task-api diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/SystemObjectCache.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/SystemObjectCache.java index 0f039ba5521..2dce6578a05 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/SystemObjectCache.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/SystemObjectCache.java @@ -12,7 +12,7 @@ import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.repo.cache.registry.CacheRegistry; +import com.evolveum.midpoint.repo.api.CacheRegistry; import com.evolveum.midpoint.repo.api.Cacheable; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.SearchResultList; diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionFactory.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionFactory.java index 5623d14fc19..179322a0deb 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionFactory.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionFactory.java @@ -21,7 +21,7 @@ import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.repo.api.Cacheable; import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.repo.cache.registry.CacheRegistry; +import com.evolveum.midpoint.repo.api.CacheRegistry; import com.evolveum.midpoint.repo.common.ObjectResolver; import com.evolveum.midpoint.repo.common.expression.ExpressionFactory; import com.evolveum.midpoint.repo.common.expression.ExpressionSyntaxException; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/triggerSetter/TriggerCreatorGlobalState.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/triggerSetter/TriggerCreatorGlobalState.java index f6c717c8aab..a09fd496726 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/triggerSetter/TriggerCreatorGlobalState.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/triggerSetter/TriggerCreatorGlobalState.java @@ -12,7 +12,7 @@ import com.evolveum.midpoint.repo.api.Cacheable; import com.evolveum.midpoint.repo.api.DeleteObjectResult; import com.evolveum.midpoint.repo.cache.invalidation.RepositoryCacheInvalidationDetails; -import com.evolveum.midpoint.repo.cache.registry.CacheRegistry; +import com.evolveum.midpoint.repo.api.CacheRegistry; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.SingleCacheStateInformationType; @@ -38,14 +38,14 @@ public class TriggerCreatorGlobalState implements Cacheable { private static final Trace LOGGER = TraceManager.getTrace(TriggerCreatorGlobalState.class); private static final Trace LOGGER_CONTENT = TraceManager.getTrace(TriggerCreatorGlobalState.class.getName() + ".content"); - private AtomicLong lastExpirationCleanup = new AtomicLong(0L); + private final AtomicLong lastExpirationCleanup = new AtomicLong(0L); private static final long EXPIRATION_INTERVAL = 10000L; @Autowired private CacheRegistry cacheRegistry; @Autowired private PrismContext prismContext; - private Map state = new ConcurrentHashMap<>(); + private final Map state = new ConcurrentHashMap<>(); synchronized CreatedTrigger getLastCreatedTrigger(TriggerHolderSpecification key) { return state.get(key); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java index e0de939f7f8..5b3b0257255 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java @@ -1496,7 +1496,7 @@ private void executeModification(Ob if (TaskType.class.isAssignableFrom(objectTypeClass)) { taskManager.modifyTask(delta.getOid(), delta.getModifications(), result); } else if (NodeType.class.isAssignableFrom(objectTypeClass)) { - throw new UnsupportedOperationException("NodeType is not modifiable using model interface"); + cacheRepositoryService.modifyObject(NodeType.class, delta.getOid(), delta.getModifications(), result); } else if (ObjectTypes.isClassManagedByProvisioning(objectTypeClass)) { ProvisioningOperationOptions provisioningOptions = getProvisioningOptions(context, options, (PrismObject) objectContext.getObjectCurrent(), (ObjectDelta) delta); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/misc/TestMisc.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/misc/TestMisc.java index 530e2b98cf9..09854217975 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/misc/TestMisc.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/misc/TestMisc.java @@ -11,8 +11,9 @@ import java.io.File; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import javax.xml.transform.dom.DOMSource; -import javax.xml.validation.Schema; import javax.xml.validation.Validator; import org.springframework.test.annotation.DirtiesContext; @@ -23,19 +24,22 @@ import com.evolveum.midpoint.model.intest.AbstractInitializedModelIntegrationTest; import com.evolveum.midpoint.prism.Objectable; -import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismReference; +import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.util.PrismAsserts; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.RepositoryDiag; import com.evolveum.midpoint.schema.SelectorOptions; +import com.evolveum.midpoint.schema.constants.ObjectTypes; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.schema.util.ShadowUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.test.DummyResourceContoller; +import com.evolveum.midpoint.test.TestResource; import com.evolveum.midpoint.test.util.TestUtil; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.exception.SystemException; @@ -53,6 +57,8 @@ public class TestMisc extends AbstractInitializedModelIntegrationTest { protected static final File ROLE_SHIP_FILE = new File(TEST_DIR, "role-ship.xml"); protected static final String ROLE_SHIP_OID = "bbd19b9a-d511-11e7-8bf7-cfecde275e59"; + private static final TestResource ARCHETYPE_NODE_GROUP_GUI = new TestResource<>(TEST_DIR, "archetype-node-group-gui.xml", "05b6933a-b7fc-4543-b8fa-fd8b278ff9ee"); + protected static final File RESOURCE_SCRIPTY_FILE = new File(TEST_DIR, "resource-dummy-scripty.xml"); protected static final String RESOURCE_SCRIPTY_OID = "399f5308-0447-11e8-91e9-a7f9c4100ffb"; protected static final String RESOURCE_DUMMY_SCRIPTY_NAME = "scripty"; @@ -75,6 +81,7 @@ public void initSystem(Task initTask, OperationResult initResult) RESOURCE_SCRIPTY_FILE, RESOURCE_SCRIPTY_OID, initTask, initResult); importObjectFromFile(ROLE_SHIP_FILE); + repoAdd(ARCHETYPE_NODE_GROUP_GUI, initResult); } @Test @@ -590,4 +597,30 @@ public void test602jackUnssigndRoleShip() throws Exception { assertLinks(userAfter, 0); } + @Test + public void test700AddNodeArchetype() throws Exception { + Task task = getTestTask(); + OperationResult result = task.getResult(); + given(); + + when(); + NodeType localNode = taskManager.getLocalNode(); + ObjectDelta delta = deltaFor(NodeType.class) + .item(NodeType.F_ASSIGNMENT) + .add(ObjectTypeUtil.createAssignmentTo(ARCHETYPE_NODE_GROUP_GUI.oid, ObjectTypes.ARCHETYPE, prismContext)) + .asObjectDelta(localNode.getOid()); + + executeChanges(delta, null, task, result); + + then(); + assertObject(NodeType.class, localNode.getOid(), "after") + .display() + .assertArchetypeRef(ARCHETYPE_NODE_GROUP_GUI.oid); + + Set localNodeGroups = taskManager.getLocalNodeGroups().stream() + .map(ObjectReferenceType::getOid) + .collect(Collectors.toSet()); + assertThat(localNodeGroups).as("local node groups") + .containsExactlyInAnyOrder(ARCHETYPE_NODE_GROUP_GUI.oid); + } } diff --git a/model/model-intest/src/test/resources/misc/archetype-node-group-gui.xml b/model/model-intest/src/test/resources/misc/archetype-node-group-gui.xml new file mode 100644 index 00000000000..d9bd79998ba --- /dev/null +++ b/model/model-intest/src/test/resources/misc/archetype-node-group-gui.xml @@ -0,0 +1,11 @@ + + + + node-group-gui + diff --git a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java index 94e4e0f9ef6..2c8ec8973a8 100644 --- a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java +++ b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java @@ -29,6 +29,8 @@ import com.evolveum.midpoint.model.api.util.ReferenceResolver; +import com.evolveum.midpoint.test.asserter.prism.PrismObjectAsserter; + import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.mutable.MutableInt; import org.jetbrains.annotations.NotNull; @@ -5851,6 +5853,16 @@ protected UserAsserter assertUser(String oid, String message) throws Objec .assertOid(oid); } + protected PrismObjectAsserter assertObject(Class clazz, String oid, String message) throws SchemaException, ObjectNotFoundException, ConfigurationException, CommunicationException, SecurityViolationException, ExpressionEvaluationException { + PrismObject object = modelService.getObject(clazz, oid, null, getTestTask(), getTestOperationResult()); + return assertObject(object, message) + .assertOid(); + } + + protected PrismObjectAsserter assertObject(PrismObject object, String message) { + return PrismObjectAsserter.forObject(object, message); + } + protected TaskAsserter assertTask(String taskOid, String message) throws SchemaException, ObjectNotFoundException { Task task = taskManager.getTaskWithResult(taskOid, getTestOperationResult()); return assertTask(task, message); diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ConnectorManager.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ConnectorManager.java index 5ade41255c9..789f8d6334d 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ConnectorManager.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ConnectorManager.java @@ -41,7 +41,7 @@ import com.evolveum.midpoint.provisioning.ucf.api.ConnectorInstance; import com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException; import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.repo.cache.registry.CacheRegistry; +import com.evolveum.midpoint.repo.api.CacheRegistry; import com.evolveum.midpoint.repo.api.Cacheable; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.internals.InternalCounters; diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceCache.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceCache.java index 01a01db660c..8a9de22d7bb 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceCache.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceCache.java @@ -11,7 +11,7 @@ import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.repo.api.Cacheable; import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.repo.cache.registry.CacheRegistry; +import com.evolveum.midpoint.repo.api.CacheRegistry; import com.evolveum.midpoint.schema.internals.InternalMonitor; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.util.caching.CachePerformanceCollector; diff --git a/repo/repo-api/src/main/java/com/evolveum/midpoint/repo/api/CacheRegistry.java b/repo/repo-api/src/main/java/com/evolveum/midpoint/repo/api/CacheRegistry.java new file mode 100644 index 00000000000..3d38679d0a0 --- /dev/null +++ b/repo/repo-api/src/main/java/com/evolveum/midpoint/repo/api/CacheRegistry.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010-2018 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ + +package com.evolveum.midpoint.repo.api; + +import com.evolveum.midpoint.xml.ns._public.common.common_3.CachesStateInformationType; + +/** + * Registry of all local cacheable services. + */ +public interface CacheRegistry { + + void registerCacheableService(Cacheable cacheableService); + + void unregisterCacheableService(Cacheable cacheableService); + + CachesStateInformationType getStateInformation(); + + void dumpContent(); +} diff --git a/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/RepositoryCache.java b/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/RepositoryCache.java index ffb1fceac61..254f08a19a0 100644 --- a/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/RepositoryCache.java +++ b/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/RepositoryCache.java @@ -18,7 +18,7 @@ import com.evolveum.midpoint.repo.cache.handlers.*; import com.evolveum.midpoint.repo.cache.local.LocalRepoCacheCollection; import com.evolveum.midpoint.repo.cache.invalidation.Invalidator; -import com.evolveum.midpoint.repo.cache.registry.CacheRegistry; +import com.evolveum.midpoint.repo.api.CacheRegistry; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; diff --git a/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/handlers/BaseOpHandler.java b/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/handlers/BaseOpHandler.java index 291fb7a88a3..bd9068f13da 100644 --- a/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/handlers/BaseOpHandler.java +++ b/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/handlers/BaseOpHandler.java @@ -18,7 +18,7 @@ import com.evolveum.midpoint.repo.cache.global.GlobalQueryCache; import com.evolveum.midpoint.repo.cache.global.GlobalVersionCache; import com.evolveum.midpoint.repo.cache.invalidation.Invalidator; -import com.evolveum.midpoint.repo.cache.registry.CacheRegistry; +import com.evolveum.midpoint.repo.api.CacheRegistry; import com.evolveum.midpoint.schema.cache.CacheConfigurationManager; /** diff --git a/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/invalidation/Invalidator.java b/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/invalidation/Invalidator.java index dfc5cf6014d..4f6c8c0f266 100644 --- a/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/invalidation/Invalidator.java +++ b/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/invalidation/Invalidator.java @@ -20,7 +20,7 @@ import com.evolveum.midpoint.repo.cache.local.LocalQueryCache; import com.evolveum.midpoint.repo.cache.local.LocalVersionCache; import com.evolveum.midpoint.repo.cache.local.QueryKey; -import com.evolveum.midpoint.repo.cache.registry.CacheRegistry; +import com.evolveum.midpoint.repo.api.CacheRegistry; import com.evolveum.midpoint.schema.SearchResultList; import com.evolveum.midpoint.schema.cache.CacheConfigurationManager; import com.evolveum.midpoint.schema.result.OperationResult; diff --git a/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/registry/CacheRegistry.java b/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/registry/CacheRegistryImpl.java similarity index 92% rename from repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/registry/CacheRegistry.java rename to repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/registry/CacheRegistryImpl.java index 078ba2c56ba..93894c0fe5c 100644 --- a/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/registry/CacheRegistry.java +++ b/repo/repo-cache/src/main/java/com/evolveum/midpoint/repo/cache/registry/CacheRegistryImpl.java @@ -11,6 +11,8 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; +import com.evolveum.midpoint.repo.api.CacheRegistry; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -28,8 +30,8 @@ * Note that this class resides in repo-cache module almost by accident and perhaps should * be moved to a more appropriate place. */ -@Component -public class CacheRegistry implements CacheListener { +@Component("cacheRegistry") +public class CacheRegistryImpl implements CacheListener, CacheRegistry { private final List cacheableServices = new ArrayList<>(); @@ -46,12 +48,14 @@ public void unregisterListener() { dispatcher.unregisterCacheListener(this); } + @Override public synchronized void registerCacheableService(Cacheable cacheableService) { if (!cacheableServices.contains(cacheableService)) { cacheableServices.add(cacheableService); } } + @Override public synchronized void unregisterCacheableService(Cacheable cacheableService) { cacheableServices.remove(cacheableService); } @@ -66,12 +70,14 @@ public void invalidate(Class type, String oid, boolean } } + @Override public CachesStateInformationType getStateInformation() { CachesStateInformationType rv = new CachesStateInformationType(prismContext); cacheableServices.forEach(cacheable -> rv.getEntry().addAll(cacheable.getStateInformation())); return rv; } + @Override public void dumpContent() { cacheableServices.forEach(Cacheable::dumpContent); } diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/SystemConfigurationCacheableAdapter.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/SystemConfigurationCacheableAdapter.java index f0b0dd45a8c..500ea187b96 100644 --- a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/SystemConfigurationCacheableAdapter.java +++ b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/SystemConfigurationCacheableAdapter.java @@ -10,7 +10,7 @@ import com.evolveum.midpoint.CacheInvalidationContext; import com.evolveum.midpoint.repo.api.Cacheable; import com.evolveum.midpoint.repo.api.SystemConfigurationChangeDispatcher; -import com.evolveum.midpoint.repo.cache.registry.CacheRegistry; +import com.evolveum.midpoint.repo.api.CacheRegistry; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/ExpressionFactory.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/ExpressionFactory.java index 031db5ca40f..40696942234 100644 --- a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/ExpressionFactory.java +++ b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/ExpressionFactory.java @@ -20,7 +20,7 @@ import com.evolveum.midpoint.common.LocalizationService; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.repo.api.Cacheable; -import com.evolveum.midpoint.repo.cache.registry.CacheRegistry; +import com.evolveum.midpoint.repo.api.CacheRegistry; import com.evolveum.midpoint.repo.common.ObjectResolver; import com.evolveum.midpoint.schema.expression.ExpressionProfile; import com.evolveum.midpoint.schema.result.OperationResult; diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/prism/PrismObjectAsserter.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/prism/PrismObjectAsserter.java index 189dc70a9fe..2a2974cb4a7 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/prism/PrismObjectAsserter.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/prism/PrismObjectAsserter.java @@ -72,12 +72,12 @@ public O getObjectable() { return object.asObjectable(); } - public static PrismObjectAsserter forObject(PrismObject shadow) { - return new PrismObjectAsserter<>(shadow); + public static PrismObjectAsserter forObject(PrismObject object) { + return new PrismObjectAsserter<>(object); } - public static PrismObjectAsserter forObject(PrismObject shadow, String details) { - return new PrismObjectAsserter<>(shadow, details); + public static PrismObjectAsserter forObject(PrismObject object, String details) { + return new PrismObjectAsserter<>(object, details); } public PrismObjectAsserter assertOid() { diff --git a/repo/task-api/src/main/java/com/evolveum/midpoint/task/api/TaskManager.java b/repo/task-api/src/main/java/com/evolveum/midpoint/task/api/TaskManager.java index 6425c9b9178..3eb2c754d37 100644 --- a/repo/task-api/src/main/java/com/evolveum/midpoint/task/api/TaskManager.java +++ b/repo/task-api/src/main/java/com/evolveum/midpoint/task/api/TaskManager.java @@ -824,4 +824,12 @@ String recordTaskThreadsDump(String taskOid, String cause, OperationResult paren * @return true if this node has recently checked in. It might be starting or up. */ boolean isCheckingIn(NodeType node); + + /** + * @return Collection of node groups that the current cluster node belongs to. + * + * The collection is unmodifiable. Groups are represented by abstract roles. + * (Current implementation uses node archetypes to keep this information.) + */ + Collection getLocalNodeGroups(); } diff --git a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskManagerQuartzImpl.java b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskManagerQuartzImpl.java index 3b460680175..4b0ce05a722 100644 --- a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskManagerQuartzImpl.java +++ b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskManagerQuartzImpl.java @@ -50,7 +50,6 @@ import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; -import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.quartz.JobKey; @@ -120,6 +119,7 @@ public class TaskManagerQuartzImpl implements TaskManager, BeanFactoryAware, Sys @Autowired private CacheConfigurationManager cacheConfigurationManager; @Autowired private Tracer tracer; @Autowired private CacheDispatcher cacheDispatcher; + @Autowired private CacheRegistry cacheRegistry; private GlobalTracingOverride globalTracingOverride; @@ -127,18 +127,19 @@ public class TaskManagerQuartzImpl implements TaskManager, BeanFactoryAware, Sys private String webContextPath; // instances of all the helper classes (see their definitions for their description) - private ExecutionManager executionManager = new ExecutionManager(this); - private ClusterManager clusterManager = new ClusterManager(this); - private StalledTasksWatcher stalledTasksWatcher = new StalledTasksWatcher(this); + // TODO Convert these to regular spring beans! + private final ExecutionManager executionManager = new ExecutionManager(this); + private final ClusterManager clusterManager = new ClusterManager(this); + private final StalledTasksWatcher stalledTasksWatcher = new StalledTasksWatcher(this); // task handlers (mapped from their URIs) - private Map handlers = new HashMap<>(); + private final Map handlers = new HashMap<>(); // primary handlers URIs - these will be taken into account when searching for handler matching a given task category - private Map primaryHandlersUris = new HashMap<>(); + private final Map primaryHandlersUris = new HashMap<>(); // all non-deprecated handlers URIs - private Map nonDeprecatedHandlersUris = new HashMap<>(); + private final Map nonDeprecatedHandlersUris = new HashMap<>(); private final Set taskDeletionListeners = new HashSet<>(); @@ -149,7 +150,7 @@ public class TaskManagerQuartzImpl implements TaskManager, BeanFactoryAware, Sys private NodeErrorStatusType nodeErrorStatus = NodeErrorStatusType.OK; // task listeners - private Set taskListeners = new HashSet<>(); + private final Set taskListeners = new HashSet<>(); /** * Registered transient tasks. Here we put all transient tasks that are to be managed by the task manager. @@ -166,7 +167,7 @@ public class TaskManagerQuartzImpl implements TaskManager, BeanFactoryAware, Sys // Maps task id -> task private final Map locallyRunningTaskInstancesMap = new ConcurrentHashMap<>(); - private ExecutorService lightweightHandlersExecutor = Executors.newCachedThreadPool(); + private final ExecutorService lightweightHandlersExecutor = Executors.newCachedThreadPool(); private BeanFactory beanFactory; @@ -226,7 +227,6 @@ public class TaskManagerQuartzImpl implements TaskManager, BeanFactoryAware, Sys @PostConstruct public void init() { - OperationResult result = createOperationResult(DOT_IMPL_CLASS + "init"); try { @@ -242,11 +242,14 @@ public void init() { if (configuration.isTestMode()) { startSchedulerIfNeeded(result); } + + clusterManager.postConstruct(); } @PreDestroy public void destroy() { systemConfigurationChangeDispatcher.unregisterListener(this); + clusterManager.preDestroy(); } @Override @@ -2703,4 +2706,19 @@ public boolean isUpAndAlive(NodeType node) { public boolean isCheckingIn(NodeType node) { return clusterManager.isCheckingIn(node); } + + @Override + public Collection getLocalNodeGroups() { + NodeType localNode = getLocalNode(); + if (localNode == null) { + // should not occur during regular operation + return emptySet(); + } else { + return Collections.unmodifiableCollection(localNode.getArchetypeRef()); + } + } + + public CacheRegistry getCacheRegistry() { + return cacheRegistry; + } } diff --git a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/cluster/ClusterManager.java b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/cluster/ClusterManager.java index 0ad67a7523f..34b2a548406 100644 --- a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/cluster/ClusterManager.java +++ b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/cluster/ClusterManager.java @@ -41,9 +41,8 @@ public class ClusterManager { private static final String CLASS_DOT = ClusterManager.class.getName() + "."; private static final String CHECK_SYSTEM_CONFIGURATION_CHANGED = CLASS_DOT + "checkSystemConfigurationChanged"; - private TaskManagerQuartzImpl taskManager; - - private NodeRegistrar nodeRegistrar; + private final TaskManagerQuartzImpl taskManager; + private final NodeRegistrar nodeRegistrar; private ClusterManagerThread clusterManagerThread; @@ -117,6 +116,14 @@ public void registerNodeUp(OperationResult result) { nodeRegistrar.registerNodeUp(result); } + public void postConstruct() { + nodeRegistrar.postConstruct(); + } + + public void preDestroy() { + nodeRegistrar.preDestroy(); + } + class ClusterManagerThread extends Thread { private boolean canRun = true; diff --git a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/cluster/NodeRegistrar.java b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/cluster/NodeRegistrar.java index 5cb56b99af1..aa41c0b0684 100644 --- a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/cluster/NodeRegistrar.java +++ b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/cluster/NodeRegistrar.java @@ -7,6 +7,7 @@ package com.evolveum.midpoint.task.quartzimpl.cluster; +import com.evolveum.midpoint.CacheInvalidationContext; import com.evolveum.midpoint.common.LocalizationService; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; @@ -17,6 +18,7 @@ import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.repo.api.Cacheable; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ObjectQueryUtil; @@ -24,6 +26,7 @@ import com.evolveum.midpoint.task.api.TaskManagerInitializationException; import com.evolveum.midpoint.task.quartzimpl.TaskManagerConfiguration; import com.evolveum.midpoint.task.quartzimpl.TaskManagerQuartzImpl; +import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.LocalizableMessageBuilder; import com.evolveum.midpoint.util.NetworkUtil; import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; @@ -37,7 +40,6 @@ import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; import org.apache.commons.lang3.RandomStringUtils; import org.jetbrains.annotations.NotNull; @@ -55,17 +57,19 @@ /** * Takes care about node registration in repository. - * - * @author Pavol Mederly */ -public class NodeRegistrar { +public class NodeRegistrar implements Cacheable { private static final Trace LOGGER = TraceManager.getTrace(NodeRegistrar.class); + private static final Trace LOGGER_CONTENT = TraceManager.getTrace(NodeRegistrar.class.getName() + ".content"); + private static final int SECRET_LENGTH = 20; private static final long SECRET_RENEWAL_PERIOD = 86400L * 1000L * 10L; - private TaskManagerQuartzImpl taskManager; - private ClusterManager clusterManager; + private static final String OP_REFRESH_CACHED_LOCAL_NODE_OBJECT = NodeRegistrar.class.getName() + ".refreshCachedLocalNodeObject"; + + private final TaskManagerQuartzImpl taskManager; + private final ClusterManager clusterManager; private long lastDiscovery; private volatile NodeOperationalStatusType operationalStatus = NodeOperationalStatusType.STARTING; @@ -78,22 +82,30 @@ public class NodeRegistrar { * In such cases we keep last 'good' information here. * * So it should be non-null in all reasonable conditions. + * + * TODO Think about thread safety of this reference. E.g. what if it is replaced unexpectedly by some 'invalidate' call? + * See MID-6324. */ - private PrismObject cachedLocalNodeObject; + private volatile PrismObject cachedLocalNodeObject; private String discoveredUrlScheme; private Integer discoveredHttpPort; NodeRegistrar(TaskManagerQuartzImpl taskManager, ClusterManager clusterManager) { - Validate.notNull(taskManager); - Validate.notNull(clusterManager); - this.taskManager = taskManager; this.clusterManager = clusterManager; discoverUrlSchemeAndPort(); } + void postConstruct() { + taskManager.getCacheRegistry().registerCacheableService(this); + } + + void preDestroy() { + taskManager.getCacheRegistry().unregisterCacheableService(this); + } + /** * Executes node startup registration: if Node object with a give name (node ID) exists, deletes it. * Then creates a new Node with the information relevant to this node. @@ -349,7 +361,7 @@ void updateNodeObject(OperationResult result) { String nodeOid = getLocalNodeObjectOid(); String nodeName = taskManager.getNodeId(); try { - setCachedLocalNodeObject(getRepositoryService().getObject(NodeType.class, nodeOid, null, result)); + refreshCachedLocalNodeObject(nodeOid, result); LOGGER.trace("Updating this node registration:\n{}", cachedLocalNodeObject.debugDumpLazily()); XMLGregorianCalendar currentTime = getCurrentTime(); @@ -380,7 +392,7 @@ void updateNodeObject(OperationResult result) { } getRepositoryService().modifyObject(NodeType.class, nodeOid, modifications, result); LOGGER.trace("Node registration successfully updated."); - setCachedLocalNodeObject(getRepositoryService().getObject(NodeType.class, nodeOid, null, result)); + refreshCachedLocalNodeObject(nodeOid, result); } catch (ObjectNotFoundException e) { LoggingUtils.logUnexpectedException(LOGGER, "Cannot update registration of this node (name {}, oid {}), because it " + "does not exist in repository. It is probably caused by cluster misconfiguration (other " @@ -401,6 +413,10 @@ void updateNodeObject(OperationResult result) { } } + private void refreshCachedLocalNodeObject(String nodeOid, OperationResult result) + throws ObjectNotFoundException, SchemaException { + setCachedLocalNodeObject(getRepositoryService().getObject(NodeType.class, nodeOid, null, result)); + } /** * Checks whether this Node object was not overwritten by another node (implying there is duplicate node ID in cluster). @@ -423,15 +439,14 @@ NodeType verifyNodeObject(OperationResult result) { "there are two or more nodes with the same name '{}'. Stopping the scheduler " + "to minimize the damage.", e, oid, myName, myName); registerNodeError(NodeErrorStatusType.DUPLICATE_NODE_ID_OR_NAME); - return null; } else { LoggingUtils.logException(LOGGER, "The record of this node cannot be read (OID {} not found). It " + "seems it was deleted in the meantime. Please check the reason. Stopping the scheduler " + "to minimize the damage.", e, oid, myName, myName); // actually we could re-register the node, but it is safer (and easier for now :) to stop the node instead registerNodeError(NodeErrorStatusType.NODE_REGISTRATION_FAILED); - return null; } + return null; } catch (SchemaException e) { LoggingUtils.logUnexpectedException(LOGGER, "Cannot check the record of this node (OID = {}) because of schema exception. Stopping the scheduler.", e, oid); registerNodeError(NodeErrorStatusType.NODE_REGISTRATION_FAILED); @@ -680,8 +695,7 @@ private PrismContext getPrismContext() { return taskManager.getPrismContext(); } - public void deleteNode(String nodeOid, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { - + void deleteNode(String nodeOid, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { OperationResult result = parentResult.createSubresult(NodeRegistrar.class.getName() + ".deleteNode"); result.addParam("nodeOid", nodeOid); @@ -708,4 +722,45 @@ void registerNodeUp(OperationResult result) { setLocalNodeOperationalStatus(NodeOperationalStatusType.UP); updateNodeObject(result); } + + @Override + public void invalidate(Class type, String oid, CacheInvalidationContext context) { + // TODO is it a good idea to fetch local node immediately on invalidation? + // Maybe we could postpone it to next call of 'get local node' + // See MID-6324. + PrismObject currentNode = this.cachedLocalNodeObject; + if (currentNode == null) { + return; // nothing to invalidate + } + if (oid != null) { + if (oid.equals(currentNode.getOid())) { + refreshCachedLocalNodeObject(currentNode.getOid()); + } + } else { + if (type == null || type.isAssignableFrom(NodeType.class)) { + refreshCachedLocalNodeObject(currentNode.getOid()); + } + } + } + + private void refreshCachedLocalNodeObject(String oid) { + OperationResult result = new OperationResult(OP_REFRESH_CACHED_LOCAL_NODE_OBJECT); + try { + refreshCachedLocalNodeObject(oid, result); + } catch (Throwable t) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't refresh cached local node object on invalidation", t); + } + } + + @Override + public @NotNull Collection getStateInformation() { + return Collections.singleton(new SingleCacheStateInformationType(taskManager.getPrismContext()) + .name(NodeRegistrar.class.getName()) + .size(cachedLocalNodeObject != null ? 1 : 0)); + } + + @Override + public void dumpContent() { + LOGGER_CONTENT.info("Current node:\n{}", DebugUtil.debugDumpLazily(cachedLocalNodeObject)); + } }