Skip to content

Commit

Permalink
Rename scope "assignee" to "linkSource"
Browse files Browse the repository at this point in the history
This is to make bulk action object set specification internally
consistent.

A part of MID-6109 implementation.
  • Loading branch information
mederly committed May 23, 2020
1 parent 5ef67d6 commit 7e02aee
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 64 deletions.
Expand Up @@ -2598,11 +2598,12 @@
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="assignee" type="c:ObjectSelectorType" minOccurs="0" maxOccurs="unbounded">
<xsd:element name="linkSource" type="c:ObjectSelectorType" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
<p>
Assignee object(s) matching given selector(s).
Objects linked to this one, matching given selector(s).
TODO find better name.
</p>
</xsd:documentation>
</xsd:annotation>
Expand Down
@@ -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<PrismObject<? extends ObjectType>> getSources(List<ObjectSelectorType> sourceSelectors) throws SchemaException,
ConfigurationException, ObjectNotFoundException, CommunicationException, SecurityViolationException,
ExpressionEvaluationException {
try {
List<PrismObject<? extends AssignmentHolderType>> allSources = getAllSources(context.getFocusContextRequired().getOid());
//noinspection unchecked
return (List) filterObjects(allSources, sourceSelectors);
} catch (Throwable t) {
result.recordFatalError(t);
throw t;
}
}

@NotNull
private List<PrismObject<? extends AssignmentHolderType>> 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<PrismObject<? extends AssignmentHolderType>> filterObjects(List<PrismObject<? extends AssignmentHolderType>> objects, List<ObjectSelectorType> selectors)
throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException,
ConfigurationException, ExpressionEvaluationException {
List<PrismObject<? extends AssignmentHolderType>> all = new ArrayList<>();
for (ObjectSelectorType selector : selectors) {
all.addAll(filterObjects(objects, selector));
}
return all;
}

private List<PrismObject<? extends AssignmentHolderType>> filterObjects(List<PrismObject<? extends AssignmentHolderType>> objects, ObjectSelectorType selector)
throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException,
ConfigurationException, ExpressionEvaluationException {
List<PrismObject<? extends AssignmentHolderType>> matching = new ArrayList<>();
for (PrismObject<? extends AssignmentHolderType> object : objects) {
if (beans.repositoryService.selectorMatches(selector, object,
null, LOGGER, "script object evaluation")) {
matching.add(object);
}
}
return matching;
}

@Override
public void close() {
result.computeStatusIfUnknown();
}
}
Expand Up @@ -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<PrismObject<? extends ObjectType>> getTargets(LinkTargetObjectSelectorType selector) {
try {
return getTargetsInternal(selector);
} catch (Throwable t) {
result.recordFatalError(t);
throw t;
}
}

List<PrismObject<? extends ObjectType>> getMatchingTargets(LinkTargetObjectSelectorType selector) {
private List<PrismObject<? extends ObjectType>> 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.
Expand Down Expand Up @@ -203,4 +214,9 @@ private Set<PrismReferenceValue> getLinkedNew() {
new HashSet<>(objectReferenceListToPrismReferenceValues(((AssignmentHolderType) objectNew).getRoleMembershipRef())) :
emptySet();
}

@Override
public void close() {
result.computeStatusIfUnknown();
}
}
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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<String, PrismObject<?>> objectsMap = new HashMap<>(); // use OID-keyed map to avoid duplicates
Map<String, PrismObject<?>> 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<PrismObject<? extends ObjectType>> assignees = getAssignees(focusContext.getOid(), task, result);
LOGGER.trace("Assignee objects (all): {}", assignees);
List<PrismObject<? extends ObjectType>> 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<PrismObject<? extends ObjectType>> 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<String, PrismObject<?>> objectsMap, List<PrismObject<? extends ObjectType>> objects) {
objects.forEach(o -> objectsMap.put(o.getOid(), o));
}

private List<PrismObject<? extends ObjectType>> filterObjects(List<PrismObject<? extends ObjectType>> objects, List<ObjectSelectorType> selectors)
throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException,
ConfigurationException, ExpressionEvaluationException {
List<PrismObject<? extends ObjectType>> all = new ArrayList<>();
for (ObjectSelectorType selector : selectors) {
all.addAll(filterObjects(objects, selector));
}
return all;
}

private List<PrismObject<? extends ObjectType>> filterObjects(List<PrismObject<? extends ObjectType>> objects, ObjectSelectorType selector)
throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException,
ConfigurationException, ExpressionEvaluationException {
List<PrismObject<? extends ObjectType>> matching = new ArrayList<>();
for (PrismObject<? extends ObjectType> object : objects) {
if (repositoryService.selectorMatches(selector, object,
null, LOGGER, "script object evaluation")) {
matching.add(object);
}
}
return matching;
}

private ValueListType createInput(Collection<PrismObject<?>> objects) {
ValueListType input = new ValueListType();
objects.forEach(o -> input.getValue().add(o.getValue().clone()));
Expand Down
Expand Up @@ -46,7 +46,7 @@
<policyActions>
<scriptExecution>
<object>
<assignee/>
<linkSource/>
</object>
<executeScript>
<s:recompute/>
Expand Down
Expand Up @@ -95,7 +95,7 @@
<policyActions>
<scriptExecution>
<object>
<assignee/>
<linkSource/>
</object>
<executeScript>
<s:recompute/>
Expand Down

0 comments on commit 7e02aee

Please sign in to comment.