Search in sources :

Example 1 with LensProjectionContext

use of com.evolveum.midpoint.model.impl.lens.LensProjectionContext in project midpoint by Evolveum.

the class ProjectionValuesProcessor method processProjections.

private <F extends FocusType> void processProjections(LensContext<F> context, LensProjectionContext projContext, String activityDescription, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException, PolicyViolationException {
    checkSchemaAndPolicies(context, projContext, activityDescription, result);
    SynchronizationPolicyDecision policyDecision = projContext.getSynchronizationPolicyDecision();
    if (policyDecision != null && policyDecision == SynchronizationPolicyDecision.UNLINK) {
        // we cannot skip deleted accounts here as the delete delta will be skipped as well
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Skipping processing of value for {} because the decision is {}", projContext.getHumanReadableName(), policyDecision);
        }
        return;
    }
    if (consistencyChecks)
        context.checkConsistence();
    if (!projContext.hasFullShadow() && hasIterationExpression(projContext)) {
        contextLoader.loadFullShadow(context, 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 unecessarily clutter the debug output.
        projContext.setOutboundConstruction(null);
        projContext.setSqueezedAttributes(null);
        projContext.setSqueezedAssociations(null);
        LOGGER.trace("Projection values iteration {}, token '{}' for {}", iteration, iterationToken, projContext.getHumanReadableName());
        if (!evaluateIterationCondition(context, projContext, iteration, iterationToken, true, task, result)) {
            conflictMessage = "pre-iteration condition was false";
            LOGGER.debug("Skipping iteration {}, token '{}' for {} because the pre-iteration condition was false", iteration, iterationToken, projContext.getHumanReadableName());
        } else {
            if (consistencyChecks)
                context.checkConsistence();
            // Re-evaluates the values in the account constructions (including roles)
            assignmentProcessor.processAssignmentsAccountValues(projContext, result);
            context.recompute();
            if (consistencyChecks)
                context.checkConsistence();
            //				LensUtil.traceContext(LOGGER, activityDescription, "values (assignment account values)", false, context, true);
            // Evaluates the values in outbound mappings
            outboundProcessor.processOutbound(context, projContext, task, result);
            context.recompute();
            if (consistencyChecks)
                context.checkConsistence();
            //				LensUtil.traceContext(LOGGER, activityDescription, "values (outbound)", false, context, true);
            // Merges the values together, processing exclusions and strong/weak mappings are needed
            consolidationProcessor.consolidateValues(context, projContext, task, result);
            if (consistencyChecks)
                context.checkConsistence();
            context.recompute();
            if (consistencyChecks)
                context.checkConsistence();
            // 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);
                LOGGER.trace("Resetting iteration counter and token because we have rename");
                if (consistencyChecks)
                    context.checkConsistence();
                continue;
            }
            if (policyDecision != null && 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<F>(projContext);
            if (skipUniquenessCheck) {
                skipUniquenessCheck = false;
                conflict = false;
            } else {
                checker.setPrismContext(prismContext);
                checker.setContext(context);
                checker.setProvisioningService(provisioningService);
                checker.check(task, result);
                if (checker.isSatisfiesConstraints()) {
                    LOGGER.trace("Current shadow satisfies uniqueness constraints. Iteration {}, token '{}'", iteration, iterationToken);
                    conflict = false;
                } else {
                    LOGGER.trace("Current shadow does not satisfy constraints. Conflicting shadow exists. Needed to found out what's wrong.");
                    if (checker.getConflictingShadow() != null) {
                        PrismObject<ShadowType> fullConflictingShadow = null;
                        try {
                            Collection<SelectorOptions<GetOperationOptions>> options = SelectorOptions.createCollection(GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE));
                            fullConflictingShadow = provisioningService.getObject(ShadowType.class, checker.getConflictingShadow().getOid(), options, task, result);
                        } 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.trace("Conflicting shadow was deleted by discovery. It does not exist anymore. Continue with adding current shadow.");
                            conflict = false;
                        }
                        result.computeStatus();
                        // the situation which happend
                        if (result.isError()) {
                            result.muteError();
                        }
                        if (conflict) {
                            PrismObject<F> focus = repositoryService.searchShadowOwner(checker.getConflictingShadow().getOid(), SelectorOptions.createCollection(GetOperationOptions.createAllowNotFound()), result);
                            //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 (focus != null && focus.getOid().equals(context.getFocusContext().getOid())) {
                                LOGGER.trace("Conflicting projection already linked to the current focus, no recompute needed, continue processing with conflicting projection.");
                                //	        			accountContext.setSecondaryDelta(null);
                                cleanupContext(projContext);
                                projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.KEEP);
                                projContext.setObjectOld(fullConflictingShadow.clone());
                                projContext.setObjectCurrent(fullConflictingShadow);
                                projContext.setFullShadow(true);
                                ObjectDelta<ShadowType> secondaryDelta = projContext.getSecondaryDelta();
                                if (secondaryDelta != null && projContext.getOid() != null) {
                                    secondaryDelta.setOid(projContext.getOid());
                                }
                                //				        			result.computeStatus();
                                //									// if the result is fatal error, it may mean that the
                                //									// already exists expection occures before..but in this
                                //									// scenario it means, the exception was handled and we
                                //									// can mute the result to give better understanding of
                                //									// the situation which happend
                                //				        			if (result.isError()){
                                //				        				result.muteError();
                                //				        			}
                                // Re-do this same iteration again (do not increase iteration count).
                                // It will recompute the values and therefore enforce the user deltas and enable reconciliation
                                // to avoid endless loop
                                skipUniquenessCheck = true;
                                continue;
                            }
                            if (focus == null) {
                                LOGGER.trace("There is no owner linked with the conflicting projection.");
                                ResourceType resourceType = projContext.getResource();
                                if (ResourceTypeUtil.isSynchronizationOpportunistic(resourceType)) {
                                    LOGGER.trace("Trying to find owner using correlation expression.");
                                    boolean match = synchronizationService.matchUserCorrelationRule(fullConflictingShadow, context.getFocusContext().getObjectNew(), resourceType, context.getSystemConfiguration(), task, result);
                                    if (match) {
                                        if (projContext.getPrimaryDelta() != null && projContext.getPrimaryDelta().isAdd()) {
                                            PrismObject<ShadowType> shadow = projContext.getPrimaryDelta().getObjectToAdd();
                                            LOGGER.trace("Found primary ADD delta of shadow {}.", shadow);
                                            LensProjectionContext conflictingAccountContext = context.findProjectionContext(projContext.getResourceShadowDiscriminator(), fullConflictingShadow.getOid());
                                            if (conflictingAccountContext == null) {
                                                conflictingAccountContext = LensUtil.createAccountContext(context, projContext.getResourceShadowDiscriminator());
                                                //													conflictingAccountContext = context.createProjectionContext(accountContext.getResourceShadowDiscriminator());
                                                conflictingAccountContext.setOid(fullConflictingShadow.getOid());
                                                conflictingAccountContext.setObjectOld(fullConflictingShadow.clone());
                                                conflictingAccountContext.setObjectCurrent(fullConflictingShadow);
                                                conflictingAccountContext.setFullShadow(true);
                                                conflictingAccountContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.KEEP);
                                                conflictingAccountContext.setResource(projContext.getResource());
                                                conflictingAccountContext.setDoReconciliation(true);
                                                conflictingAccountContext.getDependencies().clear();
                                                conflictingAccountContext.getDependencies().addAll(projContext.getDependencies());
                                                conflictingAccountContext.setWave(projContext.getWave());
                                                context.addConflictingProjectionContext(conflictingAccountContext);
                                            }
                                            projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.BROKEN);
                                            result.recordFatalError("Could not add account " + projContext.getObjectNew() + ", because the account with the same identifier already exists on the resource. ");
                                            LOGGER.error("Could not add account {}, because the account with the same identifier already exists on the resource. ", projContext.getObjectNew());
                                            // to avoid endless loop
                                            skipUniquenessCheck = true;
                                            continue;
                                        }
                                        //found shadow belongs to the current user..need to link it and replace current shadow with the found shadow..
                                        cleanupContext(projContext);
                                        projContext.setObjectOld(fullConflictingShadow.clone());
                                        projContext.setObjectCurrent(fullConflictingShadow);
                                        projContext.setFullShadow(true);
                                        projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.KEEP);
                                        ObjectDelta<ShadowType> secondaryDelta = projContext.getSecondaryDelta();
                                        if (secondaryDelta != null && projContext.getOid() != null) {
                                            secondaryDelta.setOid(projContext.getOid());
                                        }
                                        LOGGER.trace("User {} satisfies correlation rules.", context.getFocusContext().getObjectNew());
                                        // Re-do this same iteration again (do not increase iteration count).
                                        // It will recompute the values and therefore enforce the user deltas and enable reconciliation
                                        // to avoid endless loop
                                        skipUniquenessCheck = true;
                                        continue;
                                    } else {
                                        LOGGER.trace("User {} does not satisfy correlation rules.", context.getFocusContext().getObjectNew());
                                    }
                                }
                            } else {
                                LOGGER.trace("Recomputing shadow identifier, because shadow with the some identifier exists and it belongs to other user.");
                            }
                        }
                    }
                }
            }
            if (!conflict) {
                if (evaluateIterationCondition(context, projContext, iteration, iterationToken, false, task, result)) {
                    // stop the iterations
                    break;
                } else {
                    conflictMessage = "post-iteration condition was false";
                    LOGGER.debug("Skipping iteration {}, token '{}' for {} because the post-iteration condition was false", new Object[] { iteration, iterationToken, projContext.getHumanReadableName() });
                }
            } else {
                conflictMessage = checker.getMessages();
            }
        }
        iteration++;
        iterationToken = null;
        LensUtil.checkMaxIterations(iteration, maxIterations, conflictMessage, projContext.getHumanReadableName());
        cleanupContext(projContext);
        if (consistencyChecks)
            context.checkConsistence();
    }
    addIterationTokenDeltas(projContext);
    result.cleanupResult();
    if (consistencyChecks)
        context.checkConsistence();
}
Also used : ShadowType(com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType) LensProjectionContext(com.evolveum.midpoint.model.impl.lens.LensProjectionContext) ResourceType(com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType) SynchronizationPolicyDecision(com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision) SelectorOptions(com.evolveum.midpoint.schema.SelectorOptions) ObjectNotFoundException(com.evolveum.midpoint.util.exception.ObjectNotFoundException)

Example 2 with LensProjectionContext

use of com.evolveum.midpoint.model.impl.lens.LensProjectionContext in project midpoint by Evolveum.

the class AssignmentProcessor method processAssignmentsProjectionsWithFocus.

/**
     * Processing focus-projection assignments (including roles).
     */
@SuppressWarnings({ "rawtypes", "unchecked" })
private <F extends FocusType> void processAssignmentsProjectionsWithFocus(LensContext<F> context, XMLGregorianCalendar now, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException, CommunicationException, ConfigurationException, SecurityViolationException {
    // PREPARE ASSIGNMENT DELTA
    LensFocusContext<F> focusContext = context.getFocusContext();
    ObjectDelta<F> focusDelta = focusContext.getDelta();
    if (focusDelta != null && focusDelta.isDelete()) {
        processFocusDelete(context, result);
        return;
    }
    checkAssignmentDeltaSanity(context);
    // ASSIGNMENT EVALUATION
    // Initializing assignment evaluator. This will be used later to process all the assignments including the nested
    // assignments (roles).
    AssignmentEvaluator<F> assignmentEvaluator = createAssignmentEvaluator(context, now);
    ObjectType source = determineSource(focusContext);
    AssignmentTripleEvaluator<F> assignmentTripleEvaluator = new AssignmentTripleEvaluator<>();
    assignmentTripleEvaluator.setActivationComputer(activationComputer);
    assignmentTripleEvaluator.setAssignmentEvaluator(assignmentEvaluator);
    assignmentTripleEvaluator.setContext(context);
    assignmentTripleEvaluator.setNow(now);
    assignmentTripleEvaluator.setPrismContext(prismContext);
    assignmentTripleEvaluator.setResult(result);
    assignmentTripleEvaluator.setSource(source);
    assignmentTripleEvaluator.setTask(task);
    // Normal processing. The enforcement policy requires that assigned accounts should be added, so we need to figure out
    // which assignments were added. Do a complete recompute for all the enforcement modes. We can do that because this does
    // not create deltas, it just creates the triples. So we can decide what to do later when we convert triples to deltas.
    // Evaluates all assignments and sorts them to triple: added, removed and untouched assignments.
    // This is where most of the assignment-level action happens.
    DeltaSetTriple<EvaluatedAssignmentImpl<F>> evaluatedAssignmentTriple = assignmentTripleEvaluator.processAllAssignments();
    policyRuleProcessor.addGlobalPoliciesToAssignments(context, evaluatedAssignmentTriple, task, result);
    context.setEvaluatedAssignmentTriple((DeltaSetTriple) evaluatedAssignmentTriple);
    if (LOGGER.isTraceEnabled()) {
        LOGGER.trace("evaluatedAssignmentTriple:\n{}", evaluatedAssignmentTriple.debugDump());
    }
    // PROCESSING POLICIES
    policyRuleProcessor.processPolicies(context, evaluatedAssignmentTriple, result);
    boolean needToReevaluateAssignments = policyRuleProcessor.processPruning(context, evaluatedAssignmentTriple, result);
    if (needToReevaluateAssignments) {
        LOGGER.debug("Re-evaluating assignments because exclusion pruning rule was triggered");
        evaluatedAssignmentTriple = assignmentTripleEvaluator.processAllAssignments();
        context.setEvaluatedAssignmentTriple((DeltaSetTriple) evaluatedAssignmentTriple);
        policyRuleProcessor.addGlobalPoliciesToAssignments(context, evaluatedAssignmentTriple, task, result);
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("re-evaluatedAssignmentTriple:\n{}", evaluatedAssignmentTriple.debugDump());
        }
        policyRuleProcessor.processPolicies(context, evaluatedAssignmentTriple, result);
    }
    //policyRuleProcessor.storeAssignmentPolicySituation(context, evaluatedAssignmentTriple, result);
    // PROCESSING FOCUS
    Map<ItemPath, DeltaSetTriple<? extends ItemValueWithOrigin<?, ?>>> focusOutputTripleMap = new HashMap<>();
    collectFocusTripleFromMappings(evaluatedAssignmentTriple.getPlusSet(), focusOutputTripleMap, PlusMinusZero.PLUS);
    collectFocusTripleFromMappings(evaluatedAssignmentTriple.getMinusSet(), focusOutputTripleMap, PlusMinusZero.MINUS);
    collectFocusTripleFromMappings(evaluatedAssignmentTriple.getZeroSet(), focusOutputTripleMap, PlusMinusZero.ZERO);
    ObjectDeltaObject<F> focusOdo = focusContext.getObjectDeltaObject();
    Collection<ItemDelta<?, ?>> focusDeltas = objectTemplateProcessor.computeItemDeltas(focusOutputTripleMap, null, focusOdo.getObjectDelta(), focusOdo.getNewObject(), focusContext.getObjectDefinition(), "focus mappings in assignments of " + focusContext.getHumanReadableName());
    LOGGER.trace("Computed focus deltas: {}", focusDeltas);
    focusContext.applyProjectionWaveSecondaryDeltas(focusDeltas);
    focusContext.recompute();
    // PROCESSING PROJECTIONS
    // Evaluate the constructions in assignements now. These were not evaluated in the first pass of AssignmentEvaluator
    // because there may be interaction from focusMappings of some roles to outbound mappings of other roles.
    // Now we have complete focus with all the focusMappings so we can evaluate the constructions
    evaluateConstructions(context, evaluatedAssignmentTriple, task, result);
    ComplexConstructionConsumer<ResourceShadowDiscriminator, Construction<F>> consumer = new ComplexConstructionConsumer<ResourceShadowDiscriminator, Construction<F>>() {

        private boolean processOnlyExistingProjCxts;

        @Override
        public boolean before(ResourceShadowDiscriminator rat) {
            if (rat.getResourceOid() == null) {
                throw new IllegalStateException("Resource OID null in ResourceAccountType during assignment processing");
            }
            if (rat.getIntent() == null) {
                throw new IllegalStateException("Account type is null in ResourceAccountType during assignment processing");
            }
            processOnlyExistingProjCxts = false;
            if (ModelExecuteOptions.isLimitPropagation(context.getOptions())) {
                if (context.getTriggeredResourceOid() != null && !rat.getResourceOid().equals(context.getTriggeredResourceOid())) {
                    LOGGER.trace("Skipping processing construction for shadow identified by {} because of limitation to propagate changes only for resource {}", rat, context.getTriggeredResourceOid());
                    return false;
                }
                if (SchemaConstants.CHANGE_CHANNEL_DISCOVERY.equals(QNameUtil.uriToQName(context.getChannel()))) {
                    // TODO is this message OK? [med]
                    LOGGER.trace("Processing of shadow identified by {} will be skipped because of limitation for discovery channel.");
                    processOnlyExistingProjCxts = true;
                }
            }
            return true;
        }

        @Override
        public void onAssigned(ResourceShadowDiscriminator rat, String desc) {
            LensProjectionContext projectionContext = LensUtil.getOrCreateProjectionContext(context, rat);
            projectionContext.setAssigned(true);
            projectionContext.setAssignedOld(false);
            projectionContext.setLegalOld(false);
            AssignmentPolicyEnforcementType assignmentPolicyEnforcement = projectionContext.getAssignmentPolicyEnforcementType();
            if (assignmentPolicyEnforcement != AssignmentPolicyEnforcementType.NONE) {
                LOGGER.trace("Projection {} legal: assigned (valid)", desc);
                projectionContext.setLegal(true);
            }
        }

        @Override
        public void onUnchangedValid(ResourceShadowDiscriminator key, String desc) {
            LensProjectionContext projectionContext = context.findProjectionContext(key);
            if (projectionContext == null) {
                if (processOnlyExistingProjCxts) {
                    return;
                }
                // The projection should exist before the change but it does not
                // This happens during reconciliation if there is an inconsistency. 
                // Pretend that the assignment was just added. That should do.
                projectionContext = LensUtil.getOrCreateProjectionContext(context, key);
            }
            LOGGER.trace("Projection {} legal: unchanged (valid)", desc);
            projectionContext.setLegal(true);
            projectionContext.setLegalOld(true);
            projectionContext.setAssigned(true);
            projectionContext.setAssignedOld(true);
        }

        @Override
        public void onUnchangedInvalid(ResourceShadowDiscriminator rat, String desc) {
            LensProjectionContext projectionContext = context.findProjectionContext(rat);
            if (projectionContext == null) {
                if (processOnlyExistingProjCxts) {
                    return;
                }
                // The projection should exist before the change but it does not
                // This happens during reconciliation if there is an inconsistency. 
                // Pretend that the assignment was just added. That should do.
                projectionContext = LensUtil.getOrCreateProjectionContext(context, rat);
            }
            LOGGER.trace("Projection {} illegal: unchanged (invalid)", desc);
            projectionContext.setLegal(false);
            projectionContext.setLegalOld(false);
            projectionContext.setAssigned(false);
            projectionContext.setAssignedOld(false);
        }

        @Override
        public void onUnassigned(ResourceShadowDiscriminator rat, String desc) {
            if (accountExists(context, rat)) {
                LensProjectionContext projectionContext = context.findProjectionContext(rat);
                if (projectionContext == null) {
                    if (processOnlyExistingProjCxts) {
                        return;
                    }
                    projectionContext = LensUtil.getOrCreateProjectionContext(context, rat);
                }
                projectionContext.setAssigned(false);
                projectionContext.setAssignedOld(true);
                projectionContext.setLegalOld(true);
                AssignmentPolicyEnforcementType assignmentPolicyEnforcement = projectionContext.getAssignmentPolicyEnforcementType();
                // TODO: check for MARK and LEGALIZE enforcement policies ....add delete laso for relative enforcemenet
                if (assignmentPolicyEnforcement == AssignmentPolicyEnforcementType.FULL || assignmentPolicyEnforcement == AssignmentPolicyEnforcementType.RELATIVE) {
                    LOGGER.trace("Projection {} illegal: unassigned", desc);
                    projectionContext.setLegal(false);
                } else {
                    LOGGER.trace("Projection {} legal: unassigned, but allowed by policy ({})", desc, assignmentPolicyEnforcement);
                    projectionContext.setLegal(true);
                }
            } else {
                LOGGER.trace("Projection {} nothing: unassigned (valid->invalid) but not there", desc);
            // We have to delete something that is not there. Nothing to do.
            }
        }

        @Override
        public void after(ResourceShadowDiscriminator rat, String desc, DeltaMapTriple<ResourceShadowDiscriminator, ConstructionPack<Construction<F>>> constructionMapTriple) {
            PrismValueDeltaSetTriple<PrismPropertyValue<Construction>> projectionConstructionDeltaSetTriple = new PrismValueDeltaSetTriple<>(getConstructions(constructionMapTriple.getZeroMap().get(rat), true), getConstructions(constructionMapTriple.getPlusMap().get(rat), true), getConstructions(constructionMapTriple.getMinusMap().get(rat), false));
            LensProjectionContext projectionContext = context.findProjectionContext(rat);
            if (projectionContext != null) {
                // This can be null in a exotic case if we delete already deleted account
                if (LOGGER.isTraceEnabled()) {
                    LOGGER.trace("Construction delta set triple for {}:\n{}", rat, projectionConstructionDeltaSetTriple.debugDump(1));
                }
                projectionContext.setConstructionDeltaSetTriple(projectionConstructionDeltaSetTriple);
                if (isForceRecon(constructionMapTriple.getZeroMap().get(rat)) || isForceRecon(constructionMapTriple.getPlusMap().get(rat)) || isForceRecon(constructionMapTriple.getMinusMap().get(rat))) {
                    projectionContext.setDoReconciliation(true);
                }
            }
        }
    };
    constructionProcessor.processConstructions(context, evaluatedAssignmentTriple, evaluatedAssignment -> evaluatedAssignment.getConstructionTriple(), construction -> getConstructionMapKey(context, construction, task, result), consumer, task, result);
    removeIgnoredContexts(context);
    finishLegalDecisions(context);
}
Also used : PrismValueDeltaSetTriple(com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple) DeltaSetTriple(com.evolveum.midpoint.prism.delta.DeltaSetTriple) ItemDelta(com.evolveum.midpoint.prism.delta.ItemDelta) DeltaMapTriple(com.evolveum.midpoint.prism.delta.DeltaMapTriple) PrismPropertyValue(com.evolveum.midpoint.prism.PrismPropertyValue) Construction(com.evolveum.midpoint.model.impl.lens.Construction) PrismValueDeltaSetTriple(com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple) LensProjectionContext(com.evolveum.midpoint.model.impl.lens.LensProjectionContext) EvaluatedAssignmentImpl(com.evolveum.midpoint.model.impl.lens.EvaluatedAssignmentImpl) ItemValueWithOrigin(com.evolveum.midpoint.model.impl.lens.ItemValueWithOrigin) ResourceShadowDiscriminator(com.evolveum.midpoint.schema.ResourceShadowDiscriminator) ItemPath(com.evolveum.midpoint.prism.path.ItemPath)

Example 3 with LensProjectionContext

use of com.evolveum.midpoint.model.impl.lens.LensProjectionContext in project midpoint by Evolveum.

the class AssignmentProcessor method finishLegalDecisions.

/**
	 * Set 'legal' flag for the accounts that does not have it already 
	 */
private <F extends FocusType> void finishLegalDecisions(LensContext<F> context) throws PolicyViolationException, SchemaException {
    for (LensProjectionContext projectionContext : context.getProjectionContexts()) {
        if (projectionContext.isLegal() != null) {
            // already have decision
            propagateLegalDecisionToHigherOrders(context, projectionContext);
            continue;
        }
        String desc = projectionContext.toHumanReadableString();
        if (projectionContext.isLegalize()) {
            LOGGER.trace("Projection {} legal: legalized", desc);
            createAssignmentDelta(context, projectionContext);
            projectionContext.setAssigned(true);
            projectionContext.setAssignedOld(false);
            projectionContext.setLegal(true);
            projectionContext.setLegalOld(false);
        } else {
            AssignmentPolicyEnforcementType enforcementType = projectionContext.getAssignmentPolicyEnforcementType();
            if (enforcementType == AssignmentPolicyEnforcementType.FULL) {
                LOGGER.trace("Projection {} illegal: no assignment in FULL enforcement", desc);
                // What is not explicitly allowed is illegal in FULL enforcement mode
                projectionContext.setLegal(false);
                // We need to set the old value for legal to false. There was no assignment delta for it.
                // If it were then the code could not get here.
                projectionContext.setLegalOld(false);
                if (projectionContext.isAdd()) {
                    throw new PolicyViolationException("Attempt to add projection " + projectionContext.toHumanReadableString() + " while the synchronization enforcement policy is FULL and the projection is not assigned");
                }
            } else if (enforcementType == AssignmentPolicyEnforcementType.NONE && !projectionContext.isThombstone()) {
                if (projectionContext.isAdd()) {
                    LOGGER.trace("Projection {} legal: added in NONE policy", desc);
                    projectionContext.setLegal(true);
                    projectionContext.setLegalOld(false);
                } else {
                    if (projectionContext.isExists()) {
                        LOGGER.trace("Projection {} legal: exists in NONE policy", desc);
                    } else {
                        LOGGER.trace("Projection {} illegal: does not exists in NONE policy", desc);
                    }
                    // Everything that exists was legal and is legal. Nothing really changes.
                    projectionContext.setLegal(projectionContext.isExists());
                    projectionContext.setLegalOld(projectionContext.isExists());
                }
            } else if (enforcementType == AssignmentPolicyEnforcementType.POSITIVE && !projectionContext.isThombstone()) {
                // Everything that is not yet dead is legal in POSITIVE enforcement mode
                LOGGER.trace("Projection {} legal: not dead in POSITIVE policy", desc);
                projectionContext.setLegal(true);
                projectionContext.setLegalOld(true);
            } else if (enforcementType == AssignmentPolicyEnforcementType.RELATIVE && !projectionContext.isThombstone() && projectionContext.isLegal() == null && projectionContext.isLegalOld() == null) {
                // RELATIVE mode and nothing has changed. Maintain status quo. Pretend that it is legal.
                LOGGER.trace("Projection {} legal: no change in RELATIVE policy", desc);
                projectionContext.setLegal(true);
                projectionContext.setLegalOld(true);
            }
        }
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Finishing legal decision for {}, thombstone {}, enforcement mode {}, legalize {}: {} -> {}", projectionContext.toHumanReadableString(), projectionContext.isThombstone(), projectionContext.getAssignmentPolicyEnforcementType(), projectionContext.isLegalize(), projectionContext.isLegalOld(), projectionContext.isLegal());
        }
        propagateLegalDecisionToHigherOrders(context, projectionContext);
    }
}
Also used : LensProjectionContext(com.evolveum.midpoint.model.impl.lens.LensProjectionContext) PolicyViolationException(com.evolveum.midpoint.util.exception.PolicyViolationException)

Example 4 with LensProjectionContext

use of com.evolveum.midpoint.model.impl.lens.LensProjectionContext in project midpoint by Evolveum.

the class Projector method addConflictingContexts.

private <F extends ObjectType> void addConflictingContexts(LensContext<F> context) {
    List<LensProjectionContext> conflictingContexts = context.getConflictingProjectionContexts();
    if (conflictingContexts != null && !conflictingContexts.isEmpty()) {
        for (LensProjectionContext conflictingContext : conflictingContexts) {
            LOGGER.trace("Adding conflicting projection context {}", conflictingContext.getHumanReadableName());
            context.addProjectionContext(conflictingContext);
        }
        context.clearConflictingProjectionContexts();
    }
}
Also used : LensProjectionContext(com.evolveum.midpoint.model.impl.lens.LensProjectionContext)

Example 5 with LensProjectionContext

use of com.evolveum.midpoint.model.impl.lens.LensProjectionContext in project midpoint by Evolveum.

the class Projector method projectInternal.

private <F extends ObjectType> void projectInternal(LensContext<F> context, String activityDescription, boolean fromStart, boolean allWaves, Task task, OperationResult parentResult) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException {
    context.checkAbortRequested();
    if (context.getDebugListener() != null) {
        context.getDebugListener().beforeProjection(context);
    }
    // Read the time at the beginning so all processors have the same notion of "now"
    // this provides nicer unified timestamp that can be used in equality checks in tests and also for
    // troubleshooting
    XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar();
    String traceTitle = fromStart ? "projector start" : "projector resume";
    LensUtil.traceContext(LOGGER, activityDescription, traceTitle, false, context, false);
    if (consistencyChecks)
        context.checkConsistence();
    if (fromStart) {
        context.normalize();
        context.resetProjectionWave();
    }
    OperationResult result = parentResult.createSubresult(Projector.class.getName() + ".project");
    result.addParam("fromStart", fromStart);
    result.addContext("projectionWave", context.getProjectionWave());
    result.addContext("executionWave", context.getExecutionWave());
    PartialProcessingOptionsType partialProcessingOptions = context.getPartialProcessingOptions();
    try {
        context.reportProgress(new ProgressInformation(PROJECTOR, ENTERING));
        if (fromStart) {
            LensUtil.partialExecute("load", () -> {
                contextLoader.load(context, activityDescription, task, result);
                // Set the "fresh" mark now so following consistency check will be stricter
                context.setFresh(true);
                if (consistencyChecks)
                    context.checkConsistence();
            }, partialProcessingOptions::getLoad, result);
        }
        // For now let's pretend to do just one wave. The maxWaves number will be corrected in the
        // first wave when dependencies are sorted out for the first time.
        int maxWaves = context.getExecutionWave() + 1;
        // Start the waves ....
        LOGGER.trace("WAVE: Starting the waves.");
        boolean firstWave = true;
        while ((allWaves && context.getProjectionWave() < maxWaves) || (!allWaves && context.getProjectionWave() <= context.getExecutionWave())) {
            boolean inFirstWave = firstWave;
            // in order to not forget to reset it ;)
            firstWave = false;
            context.checkAbortRequested();
            LOGGER.trace("WAVE {} (maxWaves={}, executionWave={})", context.getProjectionWave(), maxWaves, context.getExecutionWave());
            //just make sure everything is loaded and set as needed
            dependencyProcessor.preprocessDependencies(context);
            // Process the focus-related aspects of the context. That means inbound, focus activation,
            // object template and assignments.
            LensUtil.partialExecute("focus", () -> {
                focusProcessor.processFocus(context, activityDescription, now, task, result);
                context.recomputeFocus();
                if (consistencyChecks)
                    context.checkConsistence();
            }, partialProcessingOptions::getFocus, result);
            LensUtil.traceContext(LOGGER, activityDescription, "focus processing", false, context, false);
            LensUtil.checkContextSanity(context, "focus processing", result);
            // a projection is provisioned or deprovisioned only after the activation is processed.
            if (fromStart && inFirstWave) {
                LOGGER.trace("Processing activation for all contexts");
                for (LensProjectionContext projectionContext : context.getProjectionContexts()) {
                    if (projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN || projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) {
                        continue;
                    }
                    activationProcessor.processActivation(context, projectionContext, now, task, result);
                    projectionContext.recompute();
                }
                // TODO move implementation of this method elsewhere; but it has to be invoked here, as activationProcessor sets the IGNORE flag
                assignmentProcessor.removeIgnoredContexts(context);
            }
            LensUtil.traceContext(LOGGER, activityDescription, "projection activation of all resources", true, context, true);
            if (consistencyChecks)
                context.checkConsistence();
            dependencyProcessor.sortProjectionsToWaves(context);
            maxWaves = dependencyProcessor.computeMaxWaves(context);
            LOGGER.trace("Continuing wave {}, maxWaves={}", context.getProjectionWave(), maxWaves);
            for (LensProjectionContext projectionContext : context.getProjectionContexts()) {
                LensUtil.partialExecute("projection " + projectionContext.getHumanReadableName(), () -> projectProjection(context, projectionContext, partialProcessingOptions, now, activityDescription, task, result), partialProcessingOptions::getProjection);
            // TODO: make this condition more complex in the future. We may want the ability
            // to select only some projections to process
            }
            // if there exists some conflicting projection contexts, add them to the context so they will be recomputed in the next wave..
            addConflictingContexts(context);
            if (consistencyChecks)
                context.checkConsistence();
            context.incrementProjectionWave();
        }
        LOGGER.trace("WAVE: Stopping the waves. There was {} waves", context.getProjectionWave());
        // We can do this only when computation of all the waves is finished. Before that we do not know
        // activation of every account and therefore cannot decide what is OK and what is not
        dependencyProcessor.checkDependenciesFinal(context, result);
        if (consistencyChecks)
            context.checkConsistence();
        computeResultStatus(now, result);
    } catch (SchemaException | PolicyViolationException | ExpressionEvaluationException | ObjectAlreadyExistsException | ObjectNotFoundException | CommunicationException | ConfigurationException | SecurityViolationException e) {
        recordFatalError(e, now, result);
        throw e;
    } catch (RuntimeException e) {
        recordFatalError(e, now, result);
        // This should not normally happen unless there is something really bad or there is a bug.
        // Make sure that it is logged.
        LOGGER.error("Runtime error in projector: {}", e.getMessage(), e);
        throw e;
    } finally {
        if (context.getDebugListener() != null) {
            context.getDebugListener().afterProjection(context);
        }
        context.reportProgress(new ProgressInformation(PROJECTOR, result));
    }
}
Also used : SchemaException(com.evolveum.midpoint.util.exception.SchemaException) ExpressionEvaluationException(com.evolveum.midpoint.util.exception.ExpressionEvaluationException) PartialProcessingOptionsType(com.evolveum.midpoint.xml.ns._public.common.common_3.PartialProcessingOptionsType) CommunicationException(com.evolveum.midpoint.util.exception.CommunicationException) SecurityViolationException(com.evolveum.midpoint.util.exception.SecurityViolationException) LensProjectionContext(com.evolveum.midpoint.model.impl.lens.LensProjectionContext) OperationResult(com.evolveum.midpoint.schema.result.OperationResult) XMLGregorianCalendar(javax.xml.datatype.XMLGregorianCalendar) ProgressInformation(com.evolveum.midpoint.model.api.ProgressInformation) ConfigurationException(com.evolveum.midpoint.util.exception.ConfigurationException) ObjectNotFoundException(com.evolveum.midpoint.util.exception.ObjectNotFoundException) PolicyViolationException(com.evolveum.midpoint.util.exception.PolicyViolationException) ObjectAlreadyExistsException(com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException)

Aggregations

LensProjectionContext (com.evolveum.midpoint.model.impl.lens.LensProjectionContext)71 ResourceShadowDiscriminator (com.evolveum.midpoint.schema.ResourceShadowDiscriminator)28 OperationResult (com.evolveum.midpoint.schema.result.OperationResult)24 Task (com.evolveum.midpoint.task.api.Task)19 ShadowType (com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType)18 Test (org.testng.annotations.Test)17 UserType (com.evolveum.midpoint.xml.ns._public.common.common_3.UserType)15 AbstractInternalModelIntegrationTest (com.evolveum.midpoint.model.impl.AbstractInternalModelIntegrationTest)14 ObjectNotFoundException (com.evolveum.midpoint.util.exception.ObjectNotFoundException)12 SchemaException (com.evolveum.midpoint.util.exception.SchemaException)11 PolicyViolationException (com.evolveum.midpoint.util.exception.PolicyViolationException)10 MockLensDebugListener (com.evolveum.midpoint.model.impl.util.mock.MockLensDebugListener)8 PrismObject (com.evolveum.midpoint.prism.PrismObject)8 ResourceObjectShadowChangeDescription (com.evolveum.midpoint.provisioning.api.ResourceObjectShadowChangeDescription)8 ObjectDelta (com.evolveum.midpoint.prism.delta.ObjectDelta)7 SynchronizationPolicyDecision (com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision)5 LensContext (com.evolveum.midpoint.model.impl.lens.LensContext)5 PrismReference (com.evolveum.midpoint.prism.PrismReference)5 ItemPath (com.evolveum.midpoint.prism.path.ItemPath)5 GetOperationOptions (com.evolveum.midpoint.schema.GetOperationOptions)5