com.evolveum.midpoint.wf.impl.processors.primary.policy.PolicyRuleBasedAspect.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.wf.impl.processors.primary.policy.PolicyRuleBasedAspect.java

Source

/*
 * Copyright (c) 2010-2017 Evolveum
 *
 * Licensed 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 com.evolveum.midpoint.wf.impl.processors.primary.policy;

import com.evolveum.midpoint.model.api.ModelInteractionService;
import com.evolveum.midpoint.model.api.context.EvaluatedAssignment;
import com.evolveum.midpoint.model.api.context.EvaluatedPolicyRule;
import com.evolveum.midpoint.model.api.context.EvaluatedPolicyRuleTrigger;
import com.evolveum.midpoint.model.api.context.PolicyRuleExternalizationOptions;
import com.evolveum.midpoint.model.api.util.EvaluatedPolicyRuleUtil;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.util.CloneUtil;
import com.evolveum.midpoint.schema.ObjectTreeDeltas;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.LocalizationUtil;
import com.evolveum.midpoint.util.LocalizableMessage;
import com.evolveum.midpoint.util.SingleLocalizableMessage;
import com.evolveum.midpoint.util.TreeNode;
import com.evolveum.midpoint.util.exception.CommonException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.wf.impl.processors.primary.ModelInvocationContext;
import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildWfTaskCreationInstruction;
import com.evolveum.midpoint.wf.impl.processors.primary.aspect.BasePrimaryChangeAspect;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.xml.namespace.QName;
import java.util.*;
import java.util.stream.Collectors;

import static com.evolveum.midpoint.prism.PrismObject.asPrismObject;
import static com.evolveum.midpoint.schema.util.LocalizationUtil.createLocalizableMessageType;
import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.createDisplayInformation;
import static com.evolveum.midpoint.wf.impl.util.MiscDataUtil.getFocusObjectNewOrOld;

/**
 *
 * @author mederly
 */
@Component
public class PolicyRuleBasedAspect extends BasePrimaryChangeAspect {

    @SuppressWarnings("unused")
    private static final Trace LOGGER = TraceManager.getTrace(PolicyRuleBasedAspect.class);

    public static final String USE_DEFAULT_NAME_MARKER = "#default#";

    @Autowired
    protected PrismContext prismContext;
    @Autowired
    private AssignmentPolicyAspectPart assignmentPolicyAspectPart;
    @Autowired
    private ObjectPolicyAspectPart objectPolicyAspectPart;
    @Autowired
    private ModelInteractionService modelInteractionService;

    //region ------------------------------------------------------------ Things that execute on request arrival

    @Override
    public boolean isEnabledByDefault() {
        return true;
    }

    @Override
    protected boolean isFirst() {
        return true;
    }

    @NotNull
    @Override
    public <T extends ObjectType> List<PcpChildWfTaskCreationInstruction<?>> prepareTasks(
            @NotNull ObjectTreeDeltas<T> objectTreeDeltas, ModelInvocationContext<T> ctx,
            @NotNull OperationResult result) throws SchemaException, ObjectNotFoundException {

        List<PcpChildWfTaskCreationInstruction<?>> instructions = new ArrayList<>();
        if (objectTreeDeltas.getFocusChange() != null) {
            PrismObject<UserType> requester = baseModelInvocationProcessingHelper.getRequester(ctx.taskFromModel,
                    result);
            assignmentPolicyAspectPart.extractAssignmentBasedInstructions(objectTreeDeltas, requester, instructions,
                    ctx, result);
            objectPolicyAspectPart.extractObjectBasedInstructions(objectTreeDeltas, requester, instructions, ctx,
                    result);
        }
        return instructions;
    }

    List<EvaluatedPolicyRule> selectTriggeredApprovalActionRules(Collection<EvaluatedPolicyRule> rules) {
        return rules.stream()
                .filter(r -> r.isTriggered() && r.containsEnabledAction(ApprovalPolicyActionType.class))
                .collect(Collectors.toList());
    }

    ApprovalSchemaType getSchemaFromAction(@NotNull ApprovalPolicyActionType approvalAction) {
        // TODO approval process
        if (approvalAction.getApprovalSchema() != null) {
            return approvalAction.getApprovalSchema().clone();
        } else {
            ApprovalSchemaType rv = new ApprovalSchemaType(prismContext);
            ApprovalStageDefinitionType stageDef = new ApprovalStageDefinitionType(prismContext);
            stageDef.getApproverRef().addAll(CloneUtil.cloneCollectionMembers(approvalAction.getApproverRef()));
            stageDef.getApproverRelation().addAll(approvalAction.getApproverRelation());
            stageDef.getApproverExpression().addAll(approvalAction.getApproverExpression());
            stageDef.setAutomaticallyApproved(approvalAction.getAutomaticallyApproved());
            // TODO maybe use name + description as well
            rv.getStage().add(stageDef);
            return rv;
        }
    }

    // evaluatedAssignment present only if relevant
    LocalizableMessage createProcessName(ApprovalSchemaBuilder.Result schemaBuilderResult,
            @Nullable EvaluatedAssignment<?> evaluatedAssignment, ModelInvocationContext<?> ctx,
            OperationResult result) {
        LocalizableMessage name = processNameFromApprovalActions(schemaBuilderResult, evaluatedAssignment, ctx,
                result);
        LOGGER.trace("Approval display name from approval actions: {}", name);
        if (name != null) {
            return name;
        }
        name = processNameFromTriggers(schemaBuilderResult);
        LOGGER.trace("Approval display name from triggers: {}", name);
        return name;
    }

    // corresponds with ConstraintEvaluationHelper.createExpressionVariables
    private LocalizableMessage processNameFromApprovalActions(ApprovalSchemaBuilder.Result schemaBuilderResult,
            @Nullable EvaluatedAssignment<?> evaluatedAssignment, ModelInvocationContext<?> ctx,
            OperationResult result) {
        if (schemaBuilderResult.approvalDisplayName == null) {
            return null;
        }
        Map<QName, Object> variables = new HashMap<>();
        variables.put(ExpressionConstants.VAR_OBJECT, getFocusObjectNewOrOld(ctx.modelContext));
        variables.put(ExpressionConstants.VAR_OBJECT_DISPLAY_INFORMATION, createLocalizableMessageType(
                createDisplayInformation(asPrismObject(getFocusObjectNewOrOld(ctx.modelContext)), false)));
        if (evaluatedAssignment != null) {
            variables.put(ExpressionConstants.VAR_TARGET, evaluatedAssignment.getTarget());
            variables.put(ExpressionConstants.VAR_TARGET_DISPLAY_INFORMATION,
                    createLocalizableMessageType(createDisplayInformation(evaluatedAssignment.getTarget(), false)));
            variables.put(ExpressionConstants.VAR_EVALUATED_ASSIGNMENT, evaluatedAssignment);
            variables.put(ExpressionConstants.VAR_ASSIGNMENT, evaluatedAssignment.getAssignmentType());
        } else {
            variables.put(ExpressionConstants.VAR_TARGET, null);
            variables.put(ExpressionConstants.VAR_TARGET_DISPLAY_INFORMATION, null);
            variables.put(ExpressionConstants.VAR_EVALUATED_ASSIGNMENT, null);
            variables.put(ExpressionConstants.VAR_ASSIGNMENT, null);
        }
        LocalizableMessageType localizableMessageType;
        try {
            localizableMessageType = modelInteractionService.createLocalizableMessageType(
                    schemaBuilderResult.approvalDisplayName, variables, ctx.taskFromModel, result);
        } catch (CommonException | RuntimeException e) {
            throw new SystemException(
                    "Couldn't create localizable message for approval display name: " + e.getMessage(), e);
        }
        return LocalizationUtil.toLocalizableMessage(localizableMessageType);
    }

    @Nullable
    private LocalizableMessage processNameFromTriggers(ApprovalSchemaBuilder.Result schemaBuilderResult) {
        List<EvaluatedPolicyRuleTriggerType> triggers = new ArrayList<>();

        // Let's analyze process specification - collect rules mentioned there.
        // Unlike in attachedRules, these are ordered in such a way that process-specific
        // are present first. (Not ordered according to composition rules.)
        if (schemaBuilderResult.processSpecification != null) {
            ProcessSpecifications.ProcessSpecification ps = schemaBuilderResult.processSpecification;
            // TODO take name from process specification itself (if present)
            for (Pair<ApprovalPolicyActionType, EvaluatedPolicyRule> actionWithRule : ps.actionsWithRules) {
                if (actionWithRule.getRight() != null) {
                    for (EvaluatedPolicyRuleTrigger<?> trigger : actionWithRule.getRight().getAllTriggers()) {
                        // we don't care about options; these converted triggers will be thrown away
                        triggers.add(
                                trigger.toEvaluatedPolicyRuleTriggerType(new PolicyRuleExternalizationOptions()));
                    }
                }
            }
        } else {
            // For assignments we do not set processSpecification yet.
            // The triggers can be collected also from attached rules.
            for (SchemaAttachedPolicyRuleType entry : schemaBuilderResult.attachedRules.getEntry()) {
                triggers.addAll(entry.getRule().getTrigger());
            }
        }

        // now get the first message
        List<TreeNode<EvaluatedPolicyRuleTriggerType>> trees = EvaluatedPolicyRuleUtil
                .arrangeForPresentationExt(triggers);
        if (!trees.isEmpty() && trees.get(0).getUserObject().getShortMessage() != null) {
            return LocalizationUtil.toLocalizableMessage(trees.get(0).getUserObject().getShortMessage());
        } else {
            return null;
        }
    }

    protected boolean useDefaultProcessName(LocalizableMessage processName) {
        return LocalizableMessage.isEmpty(processName) || processName instanceof SingleLocalizableMessage
                && USE_DEFAULT_NAME_MARKER.equals(((SingleLocalizableMessage) processName).getKey());
    }
    //endregion
}