Search in sources :

Example 16 with HookOperationMode

use of com.evolveum.midpoint.model.api.hooks.HookOperationMode in project midpoint by Evolveum.

the class WfHook method invoke.

@Override
public <O extends ObjectType> HookOperationMode invoke(@NotNull ModelContext<O> context, @NotNull Task taskFromModel, @NotNull OperationResult parentResult) {
    Validate.notNull(context);
    Validate.notNull(taskFromModel);
    Validate.notNull(parentResult);
    // Generally this cannot be minor as we need the "task switched to background" flag.
    // But if the hook does nothing (returns FOREGROUND flag), we mark the result
    // as minor afterwards.
    OperationResult result = parentResult.createSubresult(OPERATION_INVOKE);
    result.addParam("taskFromModel", taskFromModel.toString());
    result.addContext("model state", context.getState());
    try {
        WfConfigurationType wfConfigurationType = baseConfigurationHelper.getWorkflowConfiguration(context, result);
        // TODO consider this if it's secure enough
        if (wfConfigurationType != null && Boolean.FALSE.equals(wfConfigurationType.isModelHookEnabled())) {
            LOGGER.info("Workflow model hook is disabled. Proceeding with operation execution as if everything is approved.");
            result.recordSuccess();
            return HookOperationMode.FOREGROUND;
        }
        if (context.getPartialProcessingOptions().getApprovals() == PartialProcessingTypeType.SKIP) {
            LOGGER.debug("Skipping workflow processing because of the partial processing option set to SKIP");
            result.recordSuccess();
            return HookOperationMode.FOREGROUND;
        }
        // e.g. for tests, initialization is scattered through many places, so that would be too much work.
        if (SchemaConstants.CHANNEL_GUI_INIT_URI.equals(context.getChannel())) {
            LOGGER.debug("Skipping workflow processing because the channel is '" + SchemaConstants.CHANNEL_GUI_INIT_URI + "'.");
            result.recordSuccess();
            return HookOperationMode.FOREGROUND;
        }
        logOperationInformation(context);
        HookOperationMode retval = processModelInvocation(context, wfConfigurationType, taskFromModel, result);
        result.computeStatus();
        if (retval == HookOperationMode.FOREGROUND) {
            result.setMinor(true);
        }
        return retval;
    } catch (RuntimeException e) {
        result.recordFatalError("Couldn't process model invocation in workflow module: " + e.getMessage(), e);
        throw e;
    }
}
Also used : HookOperationMode(com.evolveum.midpoint.model.api.hooks.HookOperationMode) WfConfigurationType(com.evolveum.midpoint.xml.ns._public.common.common_3.WfConfigurationType) OperationResult(com.evolveum.midpoint.schema.result.OperationResult)

Example 17 with HookOperationMode

use of com.evolveum.midpoint.model.api.hooks.HookOperationMode in project midpoint by Evolveum.

the class Clockwork method runWithConflictDetection.

/**
 * Runs the clockwork with the aim of detecting modify-modify conflicts on the focus object.
 * It reports such states via the conflictResolutionContext parameter.
 */
<F extends ObjectType> HookOperationMode runWithConflictDetection(LensContext<F> context, ClockworkConflictResolver.Context conflictResolutionContext, Task task, OperationResult result) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException {
    context.setStartedIfNotYet();
    context.updateSystemConfiguration(result);
    LOGGER.trace("Running clockwork for context {}", context);
    context.checkConsistenceIfNeeded();
    context.resetClickCounter();
    try {
        context.reportProgress(new ProgressInformation(CLOCKWORK, ENTERING));
        clockworkConflictResolver.createConflictWatcherOnStart(context);
        enterCaches();
        executeInitialChecks(context);
        try {
            while (context.getState() != ModelState.FINAL) {
                context.increaseClickCounter();
                HookOperationMode mode = click(context, task, result);
                if (mode == HookOperationMode.BACKGROUND) {
                    result.setInProgress();
                    return mode;
                } else if (mode == HookOperationMode.ERROR) {
                    return mode;
                }
            }
            // One last click in FINAL state
            HookOperationMode mode = click(context, task, result);
            if (mode == HookOperationMode.FOREGROUND) {
                // We must check inside here - before watchers are unregistered
                clockworkConflictResolver.detectFocusConflicts(context, conflictResolutionContext, result);
            }
            return mode;
        } catch (ConflictDetectedException e) {
            LOGGER.debug("Clockwork conflict detected", e);
            conflictResolutionContext.recordConflictException();
            return HookOperationMode.FOREGROUND;
        }
    } finally {
        operationExecutionRecorder.recordOperationExecutions(context, task, result);
        clockworkConflictResolver.unregisterConflictWatcher(context);
        exitCaches();
        context.reportProgress(new ProgressInformation(CLOCKWORK, EXITING));
    }
}
Also used : ProgressInformation(com.evolveum.midpoint.model.api.ProgressInformation) HookOperationMode(com.evolveum.midpoint.model.api.hooks.HookOperationMode)

Example 18 with HookOperationMode

use of com.evolveum.midpoint.model.api.hooks.HookOperationMode in project midpoint by Evolveum.

the class Clockwork method run.

public <F extends ObjectType> HookOperationMode run(LensContext<F> context, Task task, OperationResult parentResult) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException {
    OperationResultBuilder builder = parentResult.subresult(OP_RUN);
    boolean tracingRequested = startTracingIfRequested(context, task, builder, parentResult);
    OperationResult result = builder.build();
    // There are some parts of processing (e.g. notifications deep in provisioning module) that have no access
    // to context.channel value, only to task.channel. So we have to get the two into sync. To return to the original
    // state, we restore task.channel afterwards.
    String originalTaskChannel = task.getChannel();
    task.setChannel(context.getChannel());
    ClockworkRunTraceType trace = null;
    try {
        trace = recordTraceAtStart(context, result);
        ClockworkConflictResolver.Context conflictResolutionContext = new ClockworkConflictResolver.Context();
        HookOperationMode mode = runWithConflictDetection(context, conflictResolutionContext, task, result);
        return clockworkConflictResolver.resolveFocusConflictIfPresent(context, conflictResolutionContext, mode, task, result);
    } catch (CommonException t) {
        result.recordFatalError(t.getMessage(), t);
        throw t;
    } finally {
        task.setChannel(originalTaskChannel);
        result.computeStatusIfUnknown();
        recordTraceAtEnd(context, trace, result);
        if (tracingRequested) {
            tracer.storeTrace(task, result, parentResult);
        }
    }
}
Also used : PrismContext(com.evolveum.midpoint.prism.PrismContext) HookOperationMode(com.evolveum.midpoint.model.api.hooks.HookOperationMode) OperationResult(com.evolveum.midpoint.schema.result.OperationResult) PolyString(com.evolveum.midpoint.prism.polystring.PolyString) OperationResultBuilder(com.evolveum.midpoint.schema.result.OperationResultBuilder)

Example 19 with HookOperationMode

use of com.evolveum.midpoint.model.api.hooks.HookOperationMode in project midpoint by Evolveum.

the class AbstractWfTestPolicy method executeTest.

protected <F extends FocusType> OperationResult executeTest(TestDetails testDetails, int expectedSubTaskCount) throws Exception {
    // GIVEN
    prepareNotifications();
    dummyAuditService.clear();
    Task opTask = getTestTask();
    boolean USE_FULL_TRACING = false;
    // noinspection ConstantConditions
    if (USE_FULL_TRACING) {
        setModelAndWorkflowLoggingTracing(opTask);
    } else {
        testDetails.setTracing(opTask);
    }
    opTask.setOwner(userAdministrator);
    OperationResult result = opTask.getResult();
    LensContext<F> modelContext = testDetails.createModelContext(result);
    displayDumpable("Model context at test start", modelContext);
    // this has problems with deleting assignments by ID
    // assertFocusModificationSanity(modelContext);
    // WHEN
    HookOperationMode mode;
    clockworkMedic.enterModelMethod(true);
    try {
        mode = clockwork.run(modelContext, opTask, result);
    } finally {
        clockworkMedic.exitModelMethod(true);
    }
    // THEN
    displayDumpable("Model context after first clockwork.run", modelContext);
    assertEquals("Unexpected state of the context", ModelState.PRIMARY, modelContext.getState());
    assertEquals("Wrong mode after clockwork.run in " + modelContext.getState(), HookOperationMode.BACKGROUND, mode);
    opTask.refresh(result);
    display("Model task after first clockwork.run", opTask);
    CaseType rootCase = testHelper.getRootCase(result);
    List<CaseType> subcases = miscHelper.getSubcases(rootCase, result);
    CaseType case0 = WfTestHelper.findAndRemoveCase0(subcases);
    assertEquals("Incorrect number of subtasks", expectedSubTaskCount, subcases.size());
    final Collection<SelectorOptions<GetOperationOptions>> options1 = schemaService.getOperationOptionsBuilder().item(T_PARENT, F_OBJECT_REF).resolve().item(T_PARENT, F_TARGET_REF).resolve().item(F_ASSIGNEE_REF).resolve().item(F_ORIGINAL_ASSIGNEE_REF).resolve().item(T_PARENT, F_REQUESTOR_REF).resolve().build();
    List<CaseWorkItemType> workItems = new // to assure modifiable result list
    ArrayList<>(modelService.searchContainers(CaseWorkItemType.class, getOpenItemsQuery(), options1, opTask, result));
    displayDumpable("changes by state after first clockwork run", approvalsManager.getChangesByState(rootCase, modelInteractionService, prismContext, opTask, result));
    testDetails.afterFirstClockworkRun(rootCase, case0, subcases, workItems, opTask, result);
    if (testDetails.executeImmediately()) {
        if (case0 != null) {
            testHelper.waitForCaseClose(case0, 20000);
        }
        displayDumpable("changes by state after case0 finishes", approvalsManager.getChangesByState(rootCase, modelInteractionService, prismContext, opTask, result));
        testDetails.afterCase0Finishes(rootCase, opTask, result);
    }
    for (int i = 0; i < subcases.size(); i++) {
        CaseType subcase = subcases.get(i);
        PrismProperty<ObjectTreeDeltasType> deltas = subcase.asPrismObject().findProperty(ItemPath.create(F_APPROVAL_CONTEXT, F_DELTAS_TO_APPROVE));
        assertNotNull("There are no modifications in subcase #" + i + ": " + subcase, deltas);
        assertEquals("Incorrect number of modifications in subcase #" + i + ": " + subcase, 1, deltas.getRealValues().size());
        // todo check correctness of the modification?
        // now check the workflow state
        String caseOid = subcase.getOid();
        List<CaseWorkItemType> caseWorkItems = getWorkItemsForCase(caseOid, null, result);
        assertFalse("work item not found", caseWorkItems.isEmpty());
        for (CaseWorkItemType caseWorkItem : caseWorkItems) {
            Boolean approve = testDetails.decideOnApproval(caseWorkItem);
            if (approve != null) {
                caseManager.completeWorkItem(WorkItemId.create(caseOid, caseWorkItem.getId()), new AbstractWorkItemOutputType(prismContext).outcome(ApprovalUtils.toUri(approve)), null, opTask, result);
                login(userAdministrator);
                break;
            }
        }
    }
    // alternative way of approvals executions
    if (CollectionUtils.isNotEmpty(testDetails.getApprovalSequence())) {
        List<ApprovalInstruction> instructions = new ArrayList<>(testDetails.getApprovalSequence());
        while (!instructions.isEmpty()) {
            List<CaseWorkItemType> currentWorkItems = modelService.searchContainers(CaseWorkItemType.class, getOpenItemsQuery(), options1, opTask, result);
            boolean matched = false;
            Collection<ApprovalInstruction> instructionsToConsider = testDetails.strictlySequentialApprovals() ? singleton(instructions.get(0)) : instructions;
            main: for (ApprovalInstruction approvalInstruction : instructionsToConsider) {
                for (CaseWorkItemType workItem : currentWorkItems) {
                    if (approvalInstruction.matches(workItem)) {
                        if (approvalInstruction.beforeApproval != null) {
                            approvalInstruction.beforeApproval.run();
                        }
                        login(getUserFromRepo(approvalInstruction.approverOid));
                        System.out.println("Completing work item " + WorkItemId.of(workItem) + " using " + approvalInstruction);
                        caseManager.completeWorkItem(WorkItemId.of(workItem), new AbstractWorkItemOutputType(prismContext).outcome(ApprovalUtils.toUri(approvalInstruction.approval)).comment(approvalInstruction.comment), null, opTask, result);
                        if (approvalInstruction.afterApproval != null) {
                            approvalInstruction.afterApproval.run();
                        }
                        login(userAdministrator);
                        matched = true;
                        instructions.remove(approvalInstruction);
                        break main;
                    }
                }
            }
            if (!matched) {
                fail("None of approval instructions " + instructionsToConsider + " matched any of current work items: " + currentWorkItems);
            }
        }
    }
    CaseType rootCaseAfter = testHelper.waitForCaseClose(rootCase, 60000);
    subcases = miscHelper.getSubcases(rootCaseAfter, result);
    WfTestHelper.findAndRemoveCase0(subcases);
    displayDumpable("changes by state after root case finishes", approvalsManager.getChangesByState(rootCaseAfter, modelInteractionService, prismContext, opTask, result));
    testDetails.afterRootCaseFinishes(rootCaseAfter, subcases, opTask, result);
    notificationManager.setDisabled(true);
    // Check audit
    displayDumpable("Audit", dummyAuditService);
    displayDumpable("Output context", modelContext);
    return result;
}
Also used : Task(com.evolveum.midpoint.task.api.Task) F_ASSIGNEE_REF(com.evolveum.midpoint.xml.ns._public.common.common_3.CaseWorkItemType.F_ASSIGNEE_REF) F_ORIGINAL_ASSIGNEE_REF(com.evolveum.midpoint.xml.ns._public.common.common_3.CaseWorkItemType.F_ORIGINAL_ASSIGNEE_REF) OperationResult(com.evolveum.midpoint.schema.result.OperationResult) HookOperationMode(com.evolveum.midpoint.model.api.hooks.HookOperationMode) CaseType(com.evolveum.midpoint.xml.ns._public.common.common_3.CaseType) SelectorOptions(com.evolveum.midpoint.schema.SelectorOptions)

Example 20 with HookOperationMode

use of com.evolveum.midpoint.model.api.hooks.HookOperationMode in project midpoint by Evolveum.

the class TestClockwork method assignAccountToJackAsync.

private void assignAccountToJackAsync(boolean serialize) throws Exception {
    given();
    Task task = getTestTask();
    OperationResult result = task.getResult();
    assertNoDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME);
    LensContext<UserType> context = createJackAssignAccountContext(result);
    assertFocusModificationSanity(context);
    mockClockworkHook.reset();
    mockClockworkHook.setRecord(true);
    mockClockworkHook.setAsynchronous(true);
    rememberCounter(InternalCounters.SHADOW_FETCH_OPERATION_COUNT);
    // WHEN
    when();
    context.setStartedIfNotYet();
    while (context.getState() != ModelState.FINAL) {
        display("CLICK START: " + context.getState());
        HookOperationMode mode = clockwork.click(context, task, result);
        display("CLICK END: " + context.getState());
        assertNotSame("Unexpected INITIAL state of the context", context.getState(), ModelState.INITIAL);
        assertEquals("Wrong mode after click in " + context.getState(), HookOperationMode.BACKGROUND, mode);
        assertCounterIncrement(InternalCounters.SHADOW_FETCH_OPERATION_COUNT, 0);
        if (serialize) {
            displayDumpable("Context before serialization", context);
            LensContextType lensContextType = context.toLensContextType();
            String xml = prismContext.xmlSerializer().serializeRealValue(lensContextType, SchemaConstants.C_MODEL_CONTEXT);
            displayValue("Serialized form", xml);
            LensContextType unmarshalledContainer = prismContext.parserFor(xml).xml().parseRealValue(LensContextType.class);
            context = LensContext.fromLensContextBean(unmarshalledContainer, task, result);
            displayValue("Context after deserialization", context.debugDump());
            context.checkConsistence();
        }
    }
    then();
    mockClockworkHook.setRecord(false);
    assertCounterIncrement(InternalCounters.SHADOW_FETCH_OPERATION_COUNT, 0);
    assertJackAssignAccountContext(context);
    assertJackAccountShadow(context);
}
Also used : Task(com.evolveum.midpoint.task.api.Task) HookOperationMode(com.evolveum.midpoint.model.api.hooks.HookOperationMode) OperationResult(com.evolveum.midpoint.schema.result.OperationResult)

Aggregations

HookOperationMode (com.evolveum.midpoint.model.api.hooks.HookOperationMode)21 OperationResult (com.evolveum.midpoint.schema.result.OperationResult)14 Task (com.evolveum.midpoint.task.api.Task)9 ObjectNotFoundException (com.evolveum.midpoint.util.exception.ObjectNotFoundException)4 SchemaException (com.evolveum.midpoint.util.exception.SchemaException)4 QName (javax.xml.namespace.QName)4 ProgressInformation (com.evolveum.midpoint.model.api.ProgressInformation)3 ModelContext (com.evolveum.midpoint.model.api.context.ModelContext)3 LensContext (com.evolveum.midpoint.model.impl.lens.LensContext)3 ExpressionEvaluationException (com.evolveum.midpoint.util.exception.ExpressionEvaluationException)3 ChangeHook (com.evolveum.midpoint.model.api.hooks.ChangeHook)2 LensProjectionContext (com.evolveum.midpoint.model.impl.lens.LensProjectionContext)2 PrismContext (com.evolveum.midpoint.prism.PrismContext)2 ObjectDelta (com.evolveum.midpoint.prism.delta.ObjectDelta)2 ItemPath (com.evolveum.midpoint.prism.path.ItemPath)2 SelectorOptions (com.evolveum.midpoint.schema.SelectorOptions)2 ObjectTypes (com.evolveum.midpoint.schema.constants.ObjectTypes)2 CommunicationException (com.evolveum.midpoint.util.exception.CommunicationException)2 ConfigurationException (com.evolveum.midpoint.util.exception.ConfigurationException)2 SecurityViolationException (com.evolveum.midpoint.util.exception.SecurityViolationException)2