Search in sources :

Example 6 with SynchronizationPolicyDecision

use of com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision in project midpoint by Evolveum.

the class ConsolidationProcessor method consolidateValuesPostRecon.

/**
 * TODO
 */
<F extends FocusType> void consolidateValuesPostRecon(LensContext<F> context, LensProjectionContext projCtx, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, PolicyViolationException {
    // account was deleted, no changes are needed.
    if (wasProjectionDeleted(projCtx)) {
        return;
    }
    SynchronizationPolicyDecision policyDecision = projCtx.getSynchronizationPolicyDecision();
    if (policyDecision == SynchronizationPolicyDecision.DELETE) {
        return;
    }
    if (!projCtx.hasFullShadow()) {
        return;
    }
    boolean addUnchangedValues = projCtx.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD;
    ObjectDelta<ShadowType> objectDelta = prismContext.deltaFactory().object().create(ShadowType.class, ChangeType.MODIFY);
    objectDelta.setOid(projCtx.getOid());
    // TODO check this
    ObjectDelta<ShadowType> existingDelta = projCtx.getSummaryDelta();
    ResourceObjectDefinition rOcDef = projCtx.getCompositeObjectDefinition();
    LOGGER.trace("Object class definition for {} post-recon consolidation:\n{}", projCtx.getResourceShadowDiscriminator(), rOcDef.debugDumpLazily());
    consolidateAttributes(projCtx, addUnchangedValues, rOcDef, objectDelta, existingDelta, StrengthSelector.WEAK_ONLY, result);
    consolidateAssociations(context, projCtx, addUnchangedValues, rOcDef, objectDelta, existingDelta, StrengthSelector.WEAK_ONLY, result);
    if (objectDelta.isEmpty()) {
        return;
    }
    projCtx.swallowToSecondaryDelta(objectDelta.getModifications());
}
Also used : SynchronizationPolicyDecision(com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision)

Example 7 with SynchronizationPolicyDecision

use of com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision in project midpoint by Evolveum.

the class LinkUpdater method setLinkedFromLegacyCriteria.

/**
 * TODO remove this code eventually
 */
private void setLinkedFromLegacyCriteria(OperationResult result) throws SchemaException, ObjectNotFoundException {
    SynchronizationPolicyDecision decision = projCtx.getSynchronizationPolicyDecision();
    SynchronizationIntent intent = projCtx.getSynchronizationIntent();
    if (decision == SynchronizationPolicyDecision.DELETE) {
        // 1. Shadow does exist in repo. So, by definition, we want to keep the link.
        // 2. But the link should be invisible, so org:related should be used.
        LOGGER.trace("Shadow is present but the decision is {}. Link should be 'related'.", decision);
        setLinkedAsRelated(result);
    } else if (decision == SynchronizationPolicyDecision.BROKEN) {
        // 3. Let us try to base our decision on synchronization intent.
        if (intent == SynchronizationIntent.UNLINK || intent == SynchronizationIntent.DELETE) {
            LOGGER.trace("Shadow is present, projection is broken, and intent was {}. Link should be 'related'.", intent);
            setLinkedAsRelated(result);
        } else {
            LOGGER.trace("Shadow is present, projection is broken, and intent was {}. Link should be 'default'.", intent);
            setLinkedNormally(result);
        }
    } else {
        LOGGER.trace("Projection seems to be alive (decision = {}). Link should be 'default'.", decision);
        setLinkedNormally(result);
    }
}
Also used : SynchronizationIntent(com.evolveum.midpoint.model.api.context.SynchronizationIntent) SynchronizationPolicyDecision(com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision)

Example 8 with SynchronizationPolicyDecision

use of com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision in project midpoint by Evolveum.

the class LinkUpdater method updateLinksInternal.

private void updateLinksInternal(OperationResult result) throws ObjectNotFoundException, SchemaException {
    SynchronizationPolicyDecision decision = projCtx.getSynchronizationPolicyDecision();
    SynchronizationIntent intent = projCtx.getSynchronizationIntent();
    LOGGER.trace("updateLinksInternal starting with sync decision: {}, sync intent: {}, gone: {}, shadow in repo: {}", decision, intent, projCtx.isGone(), projCtx.isShadowExistsInRepo());
    if (focusContext.isDelete()) {
        LOGGER.trace("Nothing to link from, because focus is being deleted. But we need to update the situation in shadow.");
        updateSituationInShadow(null, result);
    } else if (!projCtx.isShadowExistsInRepo()) {
        LOGGER.trace("Nothing to link to, because the shadow is not in repository. Removing linkRef from focus.");
        deleteLinkRefFromFocus(result);
    } else if (decision == SynchronizationPolicyDecision.UNLINK) {
        LOGGER.trace("Explicitly requested link to be removed. So removing it from the focus and the shadow.");
        deleteLinkCompletely(result);
    } else if (projCtx.isGone()) {
        if (strictMode && shadowLivenessState == null) {
            throw new IllegalStateException("Null liveness state? " + projCtx.toHumanReadableString());
        }
        if (shadowLivenessState == null || shadowLivenessState == ShadowLivenessState.DEAD) {
            LOGGER.trace("Projection is gone. Link should be 'related'.");
            setLinkedAsRelated(result);
        } else {
            if (strictMode) {
                throw new IllegalStateException("Goner with liveness state = " + shadowLivenessState + ": " + projCtx.toHumanReadableString());
            } else {
                LOGGER.warn("Projection is gone but shadow liveness state is {}. Context: {}. Setting the link " + "according to the state.", shadowLivenessState, projCtx.toHumanReadableString());
                setLinkedFromLivenessState(result);
            }
        }
    } else if (decision == SynchronizationPolicyDecision.IGNORE) {
        LOGGER.trace("Projection is ignored. Keeping link as is.");
    } else {
        if (strictMode && shadowLivenessState == null) {
            throw new IllegalStateException("Null liveness state? " + projCtx.toHumanReadableString());
        }
        setLinkedFromLivenessState(result);
    }
}
Also used : SynchronizationIntent(com.evolveum.midpoint.model.api.context.SynchronizationIntent) SynchronizationPolicyDecision(com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision)

Example 9 with SynchronizationPolicyDecision

use of com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision in project midpoint by Evolveum.

the class ProjectionValuesProcessor method processProjectionValues.

private <F extends FocusType> void processProjectionValues(LensContext<F> context, LensProjectionContext projContext, String activityDescription, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException, PolicyViolationException {
    RememberedElementState<ShadowType> rememberedProjectionState = projContext.rememberElementState();
    LOGGER.trace("Remembered projection state:\n{}", DebugUtil.debugDumpLazily(rememberedProjectionState));
    checkSchemaAndPolicies(projContext, activityDescription);
    SynchronizationPolicyDecision policyDecision = projContext.getSynchronizationPolicyDecision();
    if (policyDecision == SynchronizationPolicyDecision.UNLINK) {
        // We will not update accounts that are being unlinked.
        // we cannot skip deleted accounts here as the delete delta will be skipped as well
        LOGGER.trace("Skipping processing of value for {} because the decision is {}", projContext.getHumanReadableName(), policyDecision);
        return;
    }
    context.checkConsistenceIfNeeded();
    if (!projContext.hasFullShadow() && hasIterationExpression(projContext)) {
        contextLoader.loadFullShadow(projContext, "iteration expression", task, result);
        if (projContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN) {
            return;
        }
    }
    int maxIterations = determineMaxIterations(projContext);
    int iteration = 0;
    String iterationToken = null;
    boolean wasResetIterationCounter = false;
    PrismObject<ShadowType> shadowCurrent = projContext.getObjectCurrent();
    if (shadowCurrent != null) {
        Integer shadowIteration = shadowCurrent.asObjectable().getIteration();
        if (shadowIteration != null) {
            iteration = shadowIteration;
        }
        iterationToken = shadowCurrent.asObjectable().getIterationToken();
    }
    boolean skipUniquenessCheck = false;
    while (true) {
        projContext.setIteration(iteration);
        if (iterationToken == null) {
            iterationToken = formatIterationToken(context, projContext, iteration, task, result);
        }
        projContext.setIterationToken(iterationToken);
        String conflictMessage;
        // These are normally null. But there may be leftover from the previous iteration.
        // While that should not affect the algorithm (it should overwrite it) it may confuse
        // people during debugging and unnecessarily clutter the debug output.
        projContext.setEvaluatedPlainConstruction(null);
        projContext.setSqueezedAttributes(null);
        projContext.setSqueezedAssociations(null);
        OperationResult iterationResult = result.subresult(OP_ITERATION).addParam("iteration", iteration).addParam("iterationToken", iterationToken).build();
        try {
            LOGGER.trace("Projection values iteration {}, token '{}' for {}", iteration, iterationToken, projContext.getHumanReadableName());
            // todo remove
            LOGGER.trace("Original secondary delta:\n{}", DebugUtil.debugDumpLazily(rememberedProjectionState));
            if (!evaluateIterationCondition(context, projContext, iteration, iterationToken, true, task, iterationResult)) {
                conflictMessage = "pre-iteration condition was false";
                LOGGER.debug("Skipping iteration {}, token '{}' for {} because the pre-iteration condition was false", iteration, iterationToken, projContext.getHumanReadableName());
            } else {
                context.checkConsistenceIfNeeded();
                // Re-evaluates the values in the account constructions (including roles) - currently no-op!
                assignmentProcessor.processAssignmentsAccountValues(projContext, iterationResult);
                context.recompute();
                context.checkConsistenceIfNeeded();
                // policyRuleProcessor.evaluateShadowPolicyRules(context, projContext, activityDescription, task, iterationResult);
                // Evaluates the values in outbound mappings
                outboundProcessor.processOutbound(context, projContext, task, iterationResult);
                // Merges the values together, processing exclusions and strong/weak mappings are needed
                consolidationProcessor.consolidateValues(context, projContext, task, iterationResult);
                // Aux object classes may have changed during consolidation. Make sure we have up-to-date definitions.
                context.refreshAuxiliaryObjectClassDefinitions();
                // but I don't see any easier way to do it now.
                if (iteration != 0 && !wasResetIterationCounter && willResetIterationCounter(projContext)) {
                    wasResetIterationCounter = true;
                    iteration = 0;
                    iterationToken = null;
                    cleanupContext(projContext, null, rememberedProjectionState);
                    LOGGER.trace("Resetting iteration counter and token because we have rename");
                    context.checkConsistenceIfNeeded();
                    continue;
                }
                if (policyDecision == SynchronizationPolicyDecision.DELETE) {
                    // No need to play the iterative game if the account is deleted
                    break;
                }
                // Check constraints
                boolean conflict = true;
                ShadowConstraintsChecker<F> checker = new ShadowConstraintsChecker<>(projContext);
                ConstraintsCheckingStrategyType strategy = context.getProjectionConstraintsCheckingStrategy();
                boolean skipWhenNoIteration = strategy != null && Boolean.TRUE.equals(strategy.isSkipWhenNoIteration());
                if (skipWhenNoIteration && maxIterations == 0) {
                    LOGGER.trace("Skipping uniqueness checking because 'skipWhenNoIteration' is true and there are no iterations defined");
                    conflict = false;
                } else if (skipUniquenessCheck) {
                    LOGGER.trace("Skipping uniqueness check to avoid endless loop");
                    skipUniquenessCheck = false;
                    conflict = false;
                } else {
                    checker.setPrismContext(prismContext);
                    checker.setContext(context);
                    checker.setProvisioningService(provisioningService);
                    checker.check(task, iterationResult);
                    if (checker.isSatisfiesConstraints()) {
                        LOGGER.trace("Current shadow satisfies uniqueness constraints. Iteration {}, token '{}'", iteration, iterationToken);
                        conflict = false;
                    } else {
                        PrismObject<ShadowType> conflictingShadow = checker.getConflictingShadow();
                        if (conflictingShadow != null) {
                            LOGGER.debug("Current shadow does not satisfy constraints. It conflicts with {}. Now going to find out what's wrong.", conflictingShadow);
                            PrismObject<ShadowType> fullConflictingShadow = null;
                            try {
                                var options = SchemaService.get().getOperationOptionsBuilder().futurePointInTime().build();
                                fullConflictingShadow = provisioningService.getObject(ShadowType.class, conflictingShadow.getOid(), options, task, iterationResult);
                                LOGGER.trace("Full conflicting shadow = {}", fullConflictingShadow);
                            } catch (ObjectNotFoundException ex) {
                                // if object not found exception occurred, its ok..the account was deleted by the discovery, so there esits no more conflicting shadow
                                LOGGER.debug("Conflicting shadow was deleted by discovery. It does not exist anymore. Continue with adding current shadow.");
                                conflict = false;
                            }
                            iterationResult.computeStatus(false);
                            // the situation which happened
                            if (iterationResult.isError()) {
                                iterationResult.muteError();
                            }
                            if (conflict) {
                                PrismObject<F> conflictingShadowOwner = repositoryService.searchShadowOwner(conflictingShadow.getOid(), SelectorOptions.createCollection(GetOperationOptions.createAllowNotFound()), iterationResult);
                                LOGGER.trace("Conflicting shadow owner = {}", conflictingShadowOwner);
                                // the owner of the shadow exist and it is a current user..so the shadow was successfully created, linked etc..no other recompute is needed..
                                if (conflictingShadowOwner != null) {
                                    if (conflictingShadowOwner.getOid().equals(context.getFocusContext().getOid())) {
                                        treatConflictingWithTheSameOwner(projContext, rememberedProjectionState, fullConflictingShadow);
                                        skipUniquenessCheck = true;
                                        continue;
                                    } else {
                                        LOGGER.trace("Iterating to the following shadow identifier, because shadow with the current identifier exists and it belongs to other user.");
                                    }
                                } else {
                                    LOGGER.debug("There is no owner linked with the conflicting projection.");
                                    ResourceType resource = projContext.getResource();
                                    if (ResourceTypeUtil.isSynchronizationOpportunistic(resource)) {
                                        LOGGER.trace("Trying to find owner using correlation expression.");
                                        boolean match = synchronizationService.matchUserCorrelationRule(fullConflictingShadow, context.getFocusContext().getObjectNew(), resource, context.getSystemConfiguration(), task, iterationResult);
                                        if (match) {
                                            treatConflictWithMatchedOwner(context, projContext, iterationResult, rememberedProjectionState, fullConflictingShadow);
                                            skipUniquenessCheck = true;
                                            continue;
                                        } else {
                                            LOGGER.trace("User {} does not satisfy correlation rules.", context.getFocusContext().getObjectNew());
                                        }
                                    }
                                }
                            }
                        } else {
                            LOGGER.debug("Current shadow does not satisfy constraints, but there is no conflicting shadow. Strange.");
                        }
                    }
                }
                if (!conflict) {
                    if (evaluateIterationCondition(context, projContext, iteration, iterationToken, false, task, iterationResult)) {
                        // stop the iterations
                        break;
                    } else {
                        conflictMessage = "post-iteration condition was false";
                        LOGGER.debug("Skipping iteration {}, token '{}' for {} because the post-iteration condition was false", iteration, iterationToken, projContext.getHumanReadableName());
                    }
                } else {
                    conflictMessage = checker.getMessages();
                }
            }
        } catch (Throwable t) {
            iterationResult.recordFatalError(t);
            throw t;
        } finally {
            iterationResult.recordEnd();
            iterationResult.computeStatusIfUnknown();
        }
        iteration++;
        iterationToken = null;
        LensUtil.checkMaxIterations(iteration, maxIterations, conflictMessage, projContext.getHumanReadableName());
        cleanupContext(projContext, null, rememberedProjectionState);
        context.checkConsistenceIfNeeded();
    }
    addIterationTokenDeltas(projContext);
    context.checkConsistenceIfNeeded();
}
Also used : OperationResult(com.evolveum.midpoint.schema.result.OperationResult) SynchronizationPolicyDecision(com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision)

Example 10 with SynchronizationPolicyDecision

use of com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision in project midpoint by Evolveum.

the class LensProjectionContext method getExecutableDelta.

@Override
public ObjectDelta<ShadowType> getExecutableDelta() throws SchemaException {
    SynchronizationPolicyDecision policyDecision = getSynchronizationPolicyDecision();
    ObjectDelta<ShadowType> origDelta = getCurrentDelta();
    if (policyDecision == SynchronizationPolicyDecision.ADD) {
        // let's try to retrieve original (non-fixed) delta. Maybe it's ADD delta so we spare fixing it.
        // TODO check this
        origDelta = getSummaryDelta();
        if (origDelta == null || origDelta.isModify()) {
            // We need to convert modify delta to ADD
            ObjectDelta<ShadowType> addDelta = PrismContext.get().deltaFactory().object().create(getObjectTypeClass(), ChangeType.ADD);
            ResourceObjectDefinition objectTypeDef = getCompositeObjectDefinition();
            if (objectTypeDef == null) {
                throw new IllegalStateException("Definition for account type " + getResourceShadowDiscriminator() + " not found in the context, but it should be there");
            }
            PrismObject<ShadowType> newAccount = objectTypeDef.createBlankShadow(getResourceOid(), resourceShadowDiscriminator.getTag());
            addDelta.setObjectToAdd(newAccount);
            if (origDelta != null) {
                addDelta.merge(origDelta);
            }
            return addDelta;
        }
    } else if (policyDecision == SynchronizationPolicyDecision.KEEP) {
        // (Almost) any delta is OK
        if (exists && ObjectDelta.isAdd(origDelta)) {
            LOGGER.trace("Projection exists and we try to create it anew. This probably means that the primary ADD delta" + " should be ignored. Using secondary delta only. Current delta is:\n{}\nSecondary delta that will" + " be used instead is:\n{}", origDelta.debugDumpLazily(), DebugUtil.debugDumpLazily(getSecondaryDelta()));
            origDelta = getSecondaryDelta();
        }
    } else if (policyDecision == SynchronizationPolicyDecision.DELETE) {
        ObjectDelta<ShadowType> deleteDelta = PrismContext.get().deltaFactory().object().create(getObjectTypeClass(), ChangeType.DELETE);
        String oid = getOid();
        if (oid == null) {
            throw new IllegalStateException("Internal error: account context OID is null during attempt to create delete secondary delta; context=" + this);
        }
        deleteDelta.setOid(oid);
        return deleteDelta;
    } else {
    // This is either UNLINK or null, both are in fact the same as KEEP
    // Any delta is OK
    }
    if (origDelta != null && origDelta.isImmutable()) {
        // We need modifiable delta for execution, e.g. to set metadata, oid and so on.
        return origDelta.clone();
    } else {
        return origDelta;
    }
}
Also used : SynchronizationPolicyDecision(com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision) PolyString(com.evolveum.midpoint.prism.polystring.PolyString)

Aggregations

SynchronizationPolicyDecision (com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision)14 ActivationCapabilityType (com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationCapabilityType)4 ActivationStatusCapabilityType (com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationStatusCapabilityType)4 ActivationValidityCapabilityType (com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationValidityCapabilityType)4 SynchronizationIntent (com.evolveum.midpoint.model.api.context.SynchronizationIntent)3 OperationResult (com.evolveum.midpoint.schema.result.OperationResult)3 LensProjectionContext (com.evolveum.midpoint.model.impl.lens.LensProjectionContext)2 SynchronizationIntent (com.evolveum.midpoint.model.impl.lens.SynchronizationIntent)2 ResourceActivationDefinitionType (com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceActivationDefinitionType)2 ResourceObjectTypeDefinitionType (com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectTypeDefinitionType)2 ShadowType (com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType)2 ActivationLockoutStatusCapabilityType (com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationLockoutStatusCapabilityType)2 QName (javax.xml.namespace.QName)2 RefinedObjectClassDefinition (com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition)1 ProcessorMethod (com.evolveum.midpoint.model.impl.lens.projector.util.ProcessorMethod)1 DeltaSetTriple (com.evolveum.midpoint.prism.delta.DeltaSetTriple)1 PolyString (com.evolveum.midpoint.prism.polystring.PolyString)1 GetOperationOptions (com.evolveum.midpoint.schema.GetOperationOptions)1 SelectorOptions (com.evolveum.midpoint.schema.SelectorOptions)1 ObjectNotFoundException (com.evolveum.midpoint.util.exception.ObjectNotFoundException)1