diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd index 91c991750f5..f9605be9933 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd @@ -2598,11 +2598,12 @@ - +

- Assignee object(s) matching given selector(s). + Objects linked to this one, matching given selector(s). + TODO find better name.

diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/LinkSourceFinder.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/LinkSourceFinder.java new file mode 100644 index 00000000000..abc28664fdf --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/LinkSourceFinder.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2020 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.model.impl.lens.projector.policy; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; + +import org.jetbrains.annotations.NotNull; + +import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentHolderType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectSelectorType; + +/** + * Finds link sources based on a collection of selectors. + * + * Preliminary implementation. It is not optimizing link source search. + * Instead of creating a sophisticated query filter based on object constraints it simply + * finds all the sources and applies the constraints afterwards. + * So: TODO optimize this class + * + * TODO think if we should use model or repository when looking for objects + */ +class LinkSourceFinder implements AutoCloseable { + + private static final Trace LOGGER = TraceManager.getTrace(LinkSourceFinder.class); + + private static final String OP_GET_SOURCES = LinkSourceFinder.class.getName() + ".getSources"; + + private final PolicyRuleScriptExecutor beans; + private final LensContext context; + private final OperationResult result; + + LinkSourceFinder(PolicyRuleScriptExecutor policyRuleScriptExecutor, LensContext context, + OperationResult parentResult) { + this.beans = policyRuleScriptExecutor; + this.context = context; + this.result = parentResult.createMinorSubresult(OP_GET_SOURCES); + } + + List> getSources(List sourceSelectors) throws SchemaException, + ConfigurationException, ObjectNotFoundException, CommunicationException, SecurityViolationException, + ExpressionEvaluationException { + try { + List> allSources = getAllSources(context.getFocusContextRequired().getOid()); + //noinspection unchecked + return (List) filterObjects(allSources, sourceSelectors); + } catch (Throwable t) { + result.recordFatalError(t); + throw t; + } + } + + @NotNull + private List> getAllSources(String focusOid) throws SchemaException { + if (focusOid == null) { + LOGGER.warn("No focus object OID, no assignees can be found"); + return Collections.emptyList(); + } else { + ObjectQuery query = beans.prismContext.queryFor(AssignmentHolderType.class) + .item(AssignmentHolderType.F_ROLE_MEMBERSHIP_REF).ref(focusOid) + .build(); + //noinspection unchecked + return (List) beans.repositoryService.searchObjects(AssignmentHolderType.class, query, null, result); + } + } + + private List> filterObjects(List> objects, List selectors) + throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, + ConfigurationException, ExpressionEvaluationException { + List> all = new ArrayList<>(); + for (ObjectSelectorType selector : selectors) { + all.addAll(filterObjects(objects, selector)); + } + return all; + } + + private List> filterObjects(List> objects, ObjectSelectorType selector) + throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, + ConfigurationException, ExpressionEvaluationException { + List> matching = new ArrayList<>(); + for (PrismObject object : objects) { + if (beans.repositoryService.selectorMatches(selector, object, + null, LOGGER, "script object evaluation")) { + matching.add(object); + } + } + return matching; + } + + @Override + public void close() { + result.computeStatusIfUnknown(); + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/LinkTargetMatcher.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/LinkTargetFinder.java similarity index 90% rename from model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/LinkTargetMatcher.java rename to model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/LinkTargetFinder.java index ec7bd1de5c6..63a842b8777 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/LinkTargetMatcher.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/LinkTargetFinder.java @@ -37,27 +37,38 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.*; /** - * Selects link targets based on a collection of selectors. + * Finds link targets based on a collection of selectors. */ -class LinkTargetMatcher { +class LinkTargetFinder implements AutoCloseable { - private static final Trace LOGGER = TraceManager.getTrace(LinkTargetMatcher.class); + private static final Trace LOGGER = TraceManager.getTrace(LinkTargetFinder.class); + + private static final String OP_GET_TARGETS = LinkTargetFinder.class.getName() + ".getTargets"; @NotNull private final PolicyRuleScriptExecutor beans; @NotNull private final LensContext context; @NotNull private final EvaluatedPolicyRuleImpl rule; @NotNull private final OperationResult result; - LinkTargetMatcher(@NotNull PolicyRuleScriptExecutor policyRuleScriptExecutor, + LinkTargetFinder(@NotNull PolicyRuleScriptExecutor policyRuleScriptExecutor, @NotNull LensContext context, @NotNull EvaluatedPolicyRuleImpl rule, - @NotNull OperationResult result) { + @NotNull OperationResult parentResult) { this.beans = policyRuleScriptExecutor; this.context = context; this.rule = rule; - this.result = result; + this.result = parentResult.createMinorSubresult(OP_GET_TARGETS); + } + + List> getTargets(LinkTargetObjectSelectorType selector) { + try { + return getTargetsInternal(selector); + } catch (Throwable t) { + result.recordFatalError(t); + throw t; + } } - List> getMatchingTargets(LinkTargetObjectSelectorType selector) { + private List> getTargetsInternal(LinkTargetObjectSelectorType selector) { LOGGER.trace("Selecting matching link targets for {} with rule={}", selector, rule); // We must create new set because we will remove links from it later. @@ -203,4 +214,9 @@ private Set getLinkedNew() { new HashSet<>(objectReferenceListToPrismReferenceValues(((AssignmentHolderType) objectNew).getRoleMembershipRef())) : emptySet(); } + + @Override + public void close() { + result.computeStatusIfUnknown(); + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/PolicyRuleScriptExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/PolicyRuleScriptExecutor.java index 58871828f66..13e0f5f6730 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/PolicyRuleScriptExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/policy/PolicyRuleScriptExecutor.java @@ -13,7 +13,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; -import com.evolveum.midpoint.model.api.ModelService; import com.evolveum.midpoint.model.api.context.EvaluatedPolicyRule; import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.model.impl.lens.EvaluatedPolicyRuleImpl; @@ -24,7 +23,6 @@ import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.DeltaSetTriple; -import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.RelationRegistry; import com.evolveum.midpoint.schema.constants.ExpressionConstants; @@ -53,7 +51,6 @@ public class PolicyRuleScriptExecutor { private static final String OP_EXECUTE_SCRIPT = PolicyRuleScriptExecutor.class.getName() + ".executeScript"; - @Autowired private ModelService modelService; @Autowired PrismContext prismContext; @Autowired RelationRegistry relationRegistry; @Autowired private ScriptingExpressionEvaluator scriptingExpressionEvaluator; @@ -102,7 +99,7 @@ private void executeScript(ScriptExecutionPolicyActionType action, EvaluatedPoli try { ExecuteScriptType realExecuteScriptBean; if (specifiedExecuteScriptBean.getInput() == null && context.getFocusContext() != null) { - ValueListType input = createScriptInput(action, rule, context, context.getFocusContext(), task, result); + ValueListType input = createScriptInput(action, rule, context, context.getFocusContext(), result); realExecuteScriptBean = specifiedExecuteScriptBean.clone().input(input); } else { realExecuteScriptBean = specifiedExecuteScriptBean; @@ -119,73 +116,34 @@ private void executeScript(ScriptExecutionPolicyActionType action, EvaluatedPoli } private ValueListType createScriptInput(ScriptExecutionPolicyActionType action, EvaluatedPolicyRuleImpl rule, - LensContext context, LensFocusContext focusContext, Task task, OperationResult result) + LensContext context, LensFocusContext focusContext, OperationResult result) throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, ExpressionEvaluationException { ScriptExecutionObjectType object = action.getObject(); if (object == null) { return createInput(MiscUtil.singletonOrEmptyList(focusContext.getObjectAny())); } else { - Map> objectsMap = new HashMap<>(); // use OID-keyed map to avoid duplicates + Map> objectsMap = new HashMap<>(); // using OID-keyed map to avoid duplicates if (!object.getLinkTarget().isEmpty()) { - LinkTargetMatcher targetMatcher = new LinkTargetMatcher(this, context, rule, result); - for (LinkTargetObjectSelectorType linkTargetSelector : object.getLinkTarget()) { - addObjects(objectsMap, targetMatcher.getMatchingTargets(linkTargetSelector)); + try (LinkTargetFinder targetFinder = new LinkTargetFinder(this, context, rule, result)) { + for (LinkTargetObjectSelectorType linkTargetSelector : object.getLinkTarget()) { + addObjects(objectsMap, targetFinder.getTargets(linkTargetSelector)); + } } } - if (!object.getAssignee().isEmpty()) { - List> assignees = getAssignees(focusContext.getOid(), task, result); - LOGGER.trace("Assignee objects (all): {}", assignees); - List> filtered = filterObjects(assignees, object.getAssignee()); - LOGGER.trace("Assignee objects (filtered on selectors): {}", filtered); - addObjects(objectsMap, filtered); + if (!object.getLinkSource().isEmpty()) { + try (LinkSourceFinder sourceFinder = new LinkSourceFinder(this, context, result)) { + addObjects(objectsMap, sourceFinder.getSources(object.getLinkSource())); + } } return createInput(objectsMap.values()); } } - private List> getAssignees(String focusOid, Task task, OperationResult result) - throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, - ConfigurationException, ExpressionEvaluationException { - if (focusOid == null) { - LOGGER.warn("No focus object OID, no assignees can be found"); - return Collections.emptyList(); - } else { - ObjectQuery query = prismContext.queryFor(AssignmentHolderType.class) - .item(AssignmentHolderType.F_ROLE_MEMBERSHIP_REF).ref(focusOid) - .build(); - //noinspection unchecked - return (List) modelService.searchObjects(AssignmentHolderType.class, query, null, task, result); - } - } - private void addObjects(Map> objectsMap, List> objects) { objects.forEach(o -> objectsMap.put(o.getOid(), o)); } - private List> filterObjects(List> objects, List selectors) - throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, - ConfigurationException, ExpressionEvaluationException { - List> all = new ArrayList<>(); - for (ObjectSelectorType selector : selectors) { - all.addAll(filterObjects(objects, selector)); - } - return all; - } - - private List> filterObjects(List> objects, ObjectSelectorType selector) - throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, - ConfigurationException, ExpressionEvaluationException { - List> matching = new ArrayList<>(); - for (PrismObject object : objects) { - if (repositoryService.selectorMatches(selector, object, - null, LOGGER, "script object evaluation")) { - matching.add(object); - } - } - return matching; - } - private ValueListType createInput(Collection> objects) { ValueListType input = new ValueListType(); objects.forEach(o -> input.getValue().add(o.getValue().clone())); diff --git a/model/model-intest/src/test/resources/linked/archetype-device.xml b/model/model-intest/src/test/resources/linked/archetype-device.xml index 80178e431e5..874ad8d5b21 100644 --- a/model/model-intest/src/test/resources/linked/archetype-device.xml +++ b/model/model-intest/src/test/resources/linked/archetype-device.xml @@ -46,7 +46,7 @@ - + diff --git a/model/model-intest/src/test/resources/linked/archetype-token.xml b/model/model-intest/src/test/resources/linked/archetype-token.xml index 6819e5162bb..5a3165bb17b 100644 --- a/model/model-intest/src/test/resources/linked/archetype-token.xml +++ b/model/model-intest/src/test/resources/linked/archetype-token.xml @@ -95,7 +95,7 @@ - +