use of com.evolveum.midpoint.model.api.hooks.HookOperationMode in project midpoint by Evolveum.
the class ClockworkClick method moveStateForward.
private HookOperationMode moveStateForward(OperationResult parentResult, OperationResult result, ModelState state) throws PolicyViolationException, ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException, ConflictDetectedException {
switch(state) {
case INITIAL:
processInitialToPrimary(result);
break;
case PRIMARY:
processPrimaryToSecondary();
break;
case SECONDARY:
processSecondary(result, parentResult);
if (context.getExecutionWave() > context.getMaxWave() + 1) {
processSecondaryToFinal(context, task, result);
}
break;
case FINAL:
HookOperationMode mode = processFinal(result, parentResult);
beans.medic.clockworkFinish(context);
return mode;
}
return beans.clockworkHookHelper.invokeHooks(context, task, result);
}
use of com.evolveum.midpoint.model.api.hooks.HookOperationMode in project midpoint by Evolveum.
the class ClockworkConflictResolver method resolveFocusConflict.
private <F extends ObjectType> HookOperationMode resolveFocusConflict(LensContext<F> context, Context resolutionContext, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, ConfigurationException, CommunicationException, SecurityViolationException, PolicyViolationException, ObjectAlreadyExistsException {
ConflictResolutionType resolutionPolicy = resolutionContext.resolutionPolicy;
if (resolutionPolicy == null || resolutionPolicy.getAction() == ConflictResolutionActionType.NONE) {
if (resolutionContext.conflictExceptionPresent) {
throw new SystemException("Conflict exception present but resolution policy is null/NONE");
}
return HookOperationMode.FOREGROUND;
}
PrismObject<F> focusObject = context.getFocusContext() != null ? context.getFocusContext().getObjectAny() : null;
ModelExecuteOptions options = new ModelExecuteOptions(prismContext);
switch(resolutionPolicy.getAction()) {
case FAIL:
throw new SystemException("Conflict detected while updating " + focusObject);
case LOG:
LOGGER.warn("Conflict detected while updating {}", focusObject);
return HookOperationMode.FOREGROUND;
// TODO what to do with this?
case ERROR:
// TODO what to do with this?
case RESTART:
case RECOMPUTE:
break;
case RECONCILE:
options.reconcile();
break;
case NONE:
throw new AssertionError("Already treated");
default:
throw new IllegalStateException("Unsupported conflict resolution action: " + resolutionPolicy.getAction());
}
// so, recompute is the action
LOGGER.debug("CONFLICT: Conflict detected while updating {}, recomputing (options={})", focusObject, options);
String nonEligibilityReason = getNonEligibilityReason(context);
if (nonEligibilityReason != null) {
if (!nonEligibilityReason.isEmpty()) {
LOGGER.warn("Not eligible for conflict resolution by repetition: {}", nonEligibilityReason);
}
return HookOperationMode.FOREGROUND;
}
ConflictResolutionType focusConflictResolution = new ConflictResolutionType();
focusConflictResolution.setAction(ConflictResolutionActionType.ERROR);
options.focusConflictResolution(focusConflictResolution);
int preconditionAttempts = 0;
while (true) {
int attemptOld = context.getConflictResolutionAttemptNumber();
int attemptNew = attemptOld + 1;
boolean shouldExecuteAttempt = shouldExecuteAttempt(resolutionPolicy, attemptNew);
if (!shouldExecuteAttempt) {
LOGGER.warn("CONFLICT: Couldn't resolve conflict even after {} resolution attempt(s), giving up.", attemptOld);
return HookOperationMode.FOREGROUND;
}
delay(context, resolutionPolicy, attemptNew + preconditionAttempts);
Class<F> focusClass = context.getFocusContext().getObjectTypeClass();
String oid = context.getFocusContext().getOid();
// Not using read-only here because we are loading the focus (that will be worked with)
PrismObject<F> focus = repositoryService.getObject(focusClass, oid, null, result);
LensContext<FocusType> contextNew = contextFactory.createRecomputeContext(focus, options, task, result);
contextNew.setProgressListeners(new ArrayList<>(emptyIfNull(context.getProgressListeners())));
contextNew.setConflictResolutionAttemptNumber(attemptNew);
LOGGER.debug("CONFLICT: Recomputing {} as reaction to conflict (options={}, attempts={},{}, readVersion={})", context.getFocusContext().getHumanReadableName(), options, attemptNew, preconditionAttempts, contextNew.getFocusContext().getObjectReadVersion());
ClockworkConflictResolver.Context conflictResolutionContext = new ClockworkConflictResolver.Context();
// this is a recursion; but limited to max attempts which should not be a large number
HookOperationMode hookOperationMode = clockwork.runWithConflictDetection(contextNew, conflictResolutionContext, task, result);
if (!conflictResolutionContext.focusConflictPresent) {
LOGGER.debug("CONFLICT: Clean recompute of {} achieved (options={}, attempts={},{})", context.getFocusContext().getHumanReadableName(), options, attemptNew, preconditionAttempts);
return hookOperationMode;
}
// Actually, we could stop distinguish precondition-based and "normal" retries...
if (conflictResolutionContext.conflictExceptionPresent) {
preconditionAttempts++;
LOGGER.debug("CONFLICT: Recompute precondition failed (attempt {}, precondition attempt {}), trying again", attemptNew, preconditionAttempts);
if (preconditionAttempts < MAX_PRECONDITION_CONFLICT_RESOLUTION_ATTEMPTS) {
continue;
}
LOGGER.warn("CONFLICT: Couldn't resolve conflict even after {} resolution attempt(s) and {} precondition attempts, giving up.", attemptOld, preconditionAttempts);
return HookOperationMode.FOREGROUND;
}
}
}
use of com.evolveum.midpoint.model.api.hooks.HookOperationMode in project midpoint by Evolveum.
the class ClockworkHookHelper method invokeHooks.
/**
* Invokes hooks, if there are any.
*
* @return - ERROR, if any hook reported error; otherwise returns
* - BACKGROUND, if any hook reported switching to background; otherwise
* - FOREGROUND (if all hooks reported finishing on foreground)
*/
HookOperationMode invokeHooks(LensContext<?> context, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException, CommunicationException, ConfigurationException, SecurityViolationException {
// TODO: following two parts should be merged together in later versions
// Execute configured scripting hooks
PrismObject<SystemConfigurationType> systemConfiguration = systemObjectCache.getSystemConfiguration(result);
// systemConfiguration may be null in some tests
if (systemConfiguration != null) {
ModelHooksType modelHooks = systemConfiguration.asObjectable().getModelHooks();
if (modelHooks != null) {
HookListType changeHooks = modelHooks.getChange();
if (changeHooks != null) {
for (HookType hookType : changeHooks.getHook()) {
String shortDesc;
if (hookType.getName() != null) {
shortDesc = "hook '" + hookType.getName() + "'";
} else {
shortDesc = "scripting hook in system configuration";
}
if (hookType.isEnabled() != null && !hookType.isEnabled()) {
// Disabled hook, skip
continue;
}
if (hookType.getState() != null) {
if (!context.getState().toModelStateType().equals(hookType.getState())) {
continue;
}
}
if (hookType.getFocusType() != null) {
if (context.getFocusContext() == null) {
continue;
}
QName hookFocusTypeQname = hookType.getFocusType();
ObjectTypes hookFocusType = ObjectTypes.getObjectTypeFromTypeQName(hookFocusTypeQname);
if (hookFocusType == null) {
throw new SchemaException("Unknown focus type QName " + hookFocusTypeQname + " in " + shortDesc);
}
Class<?> focusClass = context.getFocusClass();
Class<? extends ObjectType> hookFocusClass = hookFocusType.getClassDefinition();
if (!hookFocusClass.isAssignableFrom(focusClass)) {
continue;
}
}
ScriptExpressionEvaluatorType scriptExpressionEvaluatorType = hookType.getScript();
if (scriptExpressionEvaluatorType == null) {
continue;
}
try {
evaluateScriptingHook(context, scriptExpressionEvaluatorType, shortDesc, task, result);
} catch (ExpressionEvaluationException e) {
LOGGER.error("Evaluation of {} failed: {}", shortDesc, e.getMessage(), e);
throw new ExpressionEvaluationException("Evaluation of " + shortDesc + " failed: " + e.getMessage(), e);
} catch (ObjectNotFoundException e) {
LOGGER.error("Evaluation of {} failed: {}", shortDesc, e.getMessage(), e);
throw new ObjectNotFoundException("Evaluation of " + shortDesc + " failed: " + e.getMessage(), e);
} catch (SchemaException e) {
LOGGER.error("Evaluation of {} failed: {}", shortDesc, e.getMessage(), e);
throw new SchemaException("Evaluation of " + shortDesc + " failed: " + e.getMessage(), e);
} catch (CommunicationException e) {
LOGGER.error("Evaluation of {} failed: {}", shortDesc, e.getMessage(), e);
throw new CommunicationException("Evaluation of " + shortDesc + " failed: " + e.getMessage(), e);
} catch (ConfigurationException e) {
LOGGER.error("Evaluation of {} failed: {}", shortDesc, e.getMessage(), e);
throw new ConfigurationException("Evaluation of " + shortDesc + " failed: " + e.getMessage(), e);
} catch (SecurityViolationException e) {
LOGGER.error("Evaluation of {} failed: {}", shortDesc, e.getMessage(), e);
throw new SecurityViolationException("Evaluation of " + shortDesc + " failed: " + e.getMessage(), e);
}
}
}
}
}
// Execute registered Java hooks
HookOperationMode resultMode = HookOperationMode.FOREGROUND;
if (hookRegistry != null) {
for (ChangeHook hook : hookRegistry.getAllChangeHooks()) {
HookOperationMode mode = hook.invoke(context, task, result);
if (mode == HookOperationMode.ERROR) {
resultMode = HookOperationMode.ERROR;
} else if (mode == HookOperationMode.BACKGROUND) {
if (resultMode != HookOperationMode.ERROR) {
resultMode = HookOperationMode.BACKGROUND;
}
}
}
}
return resultMode;
}
use of com.evolveum.midpoint.model.api.hooks.HookOperationMode in project midpoint by Evolveum.
the class TestAddAssociation method test100AddJackToGuests.
/**
* Add entitlement for 'guests' to user jack - should be created without starting wf process
*/
@Test
public void test100AddJackToGuests() throws Exception {
Task modelTask = getTestTask();
OperationResult result = createOperationResult();
modelTask.setOwner(repositoryService.getObject(UserType.class, USER_ADMINISTRATOR_OID, null, result));
LensContext<UserType> context = createUserLensContext();
fillContextWithUser(context, USER_JACK_OID, result);
UserType jack = context.getFocusContext().getObjectCurrent().asObjectable();
AssertJUnit.assertEquals("Jack has wrong number of accounts", 1, jack.getLinkRef().size());
jackAccountShadowOid = jack.getLinkRef().get(0).getOid();
ShadowType accountBefore = getObject(ShadowType.class, jackAccountShadowOid).asObjectable();
assertEquals("Wrong # of jack's account associations", 1, accountBefore.getAssociation().size());
assertHasAssociation(accountBefore, new QName("group"), SHADOW_TESTERS_OID);
LensProjectionContext accountContext = fillContextWithAccount(context, jackAccountShadowOid, modelTask, result);
ObjectModificationType modElement = PrismTestUtil.parseAtomicValue(REQ_ADD_ENTITLEMENT_GUESTS, ObjectModificationType.COMPLEX_TYPE);
ObjectDelta shadowDelta = DeltaConvertor.createObjectDelta(modElement, ShadowType.class, prismContext);
shadowDelta.setOid(jackAccountShadowOid);
// noinspection unchecked
accountContext.setPrimaryDelta(shadowDelta);
HookOperationMode mode = clockwork.run(context, modelTask, result);
assertEquals("Unexpected state of the context - workflow was started even if it should not", ModelState.FINAL, context.getState());
assertEquals("Wrong mode after clockwork.run in " + context.getState(), HookOperationMode.FOREGROUND, mode);
ShadowType accountAfter = getObject(ShadowType.class, jackAccountShadowOid).asObjectable();
assertEquals("Wrong # of jack's account associations", 2, accountAfter.getAssociation().size());
assertHasAssociation(accountAfter, new QName("group"), SHADOW_TESTERS_OID);
assertHasAssociation(accountAfter, new QName("group"), SHADOW_GUESTS_OID);
}
use of com.evolveum.midpoint.model.api.hooks.HookOperationMode in project midpoint by Evolveum.
the class TestAddAssociation method executeTest.
private void executeTest(String testName, String focusOid, TestDetails testDetails) throws Exception {
// GIVEN
prepareNotifications();
dummyAuditService.clear();
OperationResult result = new OperationResult("execution");
Task task = taskManager.createTaskInstance(TestAddAssociation.class.getName() + "." + testName);
task.setOwner(userAdministrator);
if (focusOid != null && testDetails.removeAssignmentsBeforeTest()) {
removeAllAssignments(focusOid, result);
}
// noinspection unchecked
LensContext<UserType> context = (LensContext<UserType>) testDetails.createModelContext(task, result);
displayDumpable("Input context", context);
assertFocusModificationSanity(context);
// WHEN
HookOperationMode mode = clockwork.run(context, task, result);
// THEN
assertEquals("Unexpected state of the context", ModelState.PRIMARY, context.getState());
assertEquals("Wrong mode after clockwork.run in " + context.getState(), HookOperationMode.BACKGROUND, mode);
CaseType rootCase = testHelper.getRootCase(result);
if (!testDetails.approvedAutomatically()) {
List<CaseType> subcases = miscHelper.getSubcases(rootCase, result);
assertEquals("Incorrect number of subcases", testDetails.subcasesCount(), subcases.size());
CaseType case0 = WfTestHelper.findAndRemoveCase0(subcases);
testDetails.assertsAfterClockworkRun(rootCase, case0, subcases, task, result);
if (testDetails.immediate()) {
CaseType rootCaseAfter = testHelper.waitForCaseClose(case0, 20000);
testDetails.assertsAfterImmediateExecutionFinished(rootCaseAfter, result);
}
for (int i = 0; i < subcases.size(); i++) {
CaseType subcase = subcases.get(i);
// noinspection unchecked
PrismProperty<ObjectTreeDeltasType> deltas = subcase.asPrismContainerValue().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
// WfProcessInstanceType processInstance = workflowServiceImpl.getProcessInstanceById(pid, false, true, result);
// assertNotNull("Process instance information cannot be retrieved", processInstance);
// assertEquals("Incorrect number of work items", 1, processInstance.getWorkItems().size());
// String taskId = processInstance.getWorkItems().get(0).getWorkItemId();
// WorkItemDetailed workItemDetailed = wfDataAccessor.getWorkItemDetailsById(taskId, result);
List<CaseWorkItemType> workItems = getWorkItemsForCase(subcase.getOid(), null, result);
CaseWorkItemType workItem = MiscUtil.extractSingleton(workItems);
assertNotNull("work item not found", workItem);
ApprovalContextType wfContext = subcase.getApprovalContext();
logger.trace("wfContext = {}", wfContext);
boolean approve = testDetails.decideOnApproval(subcase, wfContext);
caseManager.completeWorkItem(WorkItemId.of(workItem), new AbstractWorkItemOutputType(prismContext).outcome(ApprovalUtils.toUri(approve)), null, task, result);
login(userAdministrator);
}
}
CaseType rootCaseAfter = testHelper.waitForCaseClose(rootCase, 60000);
List<CaseType> subcases = miscHelper.getSubcases(rootCaseAfter, result);
WfTestHelper.findAndRemoveCase0(subcases);
// TestUtil.assertSuccess(rootCase.getResult());
testDetails.assertsRootCaseFinishes(rootCaseAfter, subcases, task, result);
if (focusOid == null) {
focusOid = testDetails.getObjectOid(rootCaseAfter, result);
}
assertNotNull("object oid is null after operation", focusOid);
if (!focusOid.equals(DONT_CHECK)) {
assertObjectInTaskTree(rootCaseAfter, focusOid, testDetails.checkObjectOnSubtasks(), result);
}
if (!testDetails.approvedAutomatically()) {
// ZZZ temporarily disabled
// checkDummyTransportMessages("simpleWorkflowNotifier-Processes", workflowSubtaskCount * 2);
// checkDummyTransportMessages("simpleWorkflowNotifier-WorkItems", workflowSubtaskCount * 2);
}
notificationManager.setDisabled(true);
// Check audit
displayDumpable("Audit", dummyAuditService);
displayDumpable("Output context", context);
}
Aggregations