Search in sources :

Example 41 with Duration

use of javax.xml.datatype.Duration in project midpoint by Evolveum.

the class ShadowCaretaker method findPreviousPendingLifecycleOperationInGracePeriod.

public ChangeTypeType findPreviousPendingLifecycleOperationInGracePeriod(@Nullable ProvisioningContext ctx, @NotNull PrismObject<ShadowType> shadow, @NotNull XMLGregorianCalendar now) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException {
    List<PendingOperationType> pendingOperations = shadow.asObjectable().getPendingOperation();
    if (pendingOperations.isEmpty()) {
        return null;
    }
    Duration gracePeriod = ctx != null ? ProvisioningUtil.getGracePeriod(ctx) : null;
    ChangeTypeType found = null;
    for (PendingOperationType pendingOperation : pendingOperations) {
        ObjectDeltaType delta = pendingOperation.getDelta();
        if (delta == null) {
            continue;
        }
        ChangeTypeType changeType = delta.getChangeType();
        if (ChangeTypeType.MODIFY.equals(changeType)) {
            continue;
        }
        if (ProvisioningUtil.isOverPeriod(now, gracePeriod, pendingOperation)) {
            continue;
        }
        if (changeType == ChangeTypeType.DELETE) {
            // DELETE always wins
            return changeType;
        } else {
            // If there is an ADD then let's check for delete.
            found = changeType;
        }
    }
    return found;
}
Also used : ObjectDeltaType(com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType) ChangeTypeType(com.evolveum.prism.xml.ns._public.types_3.ChangeTypeType) Duration(javax.xml.datatype.Duration)

Example 42 with Duration

use of javax.xml.datatype.Duration in project midpoint by Evolveum.

the class ShadowCaretaker method applyPendingOperations.

public PrismObject<ShadowType> applyPendingOperations(ProvisioningContext ctx, PrismObject<ShadowType> repoShadow, PrismObject<ShadowType> resourceShadow, boolean skipExecutionPendingOperations, XMLGregorianCalendar now) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException, ExpressionEvaluationException {
    if (repoShadow == null) {
        return resourceShadow;
    }
    PrismObject<ShadowType> resultShadow;
    if (resourceShadow == null) {
        resultShadow = repoShadow;
    } else {
        resultShadow = resourceShadow;
    }
    if (ShadowUtil.isDead(resultShadow)) {
        return resultShadow;
    }
    List<PendingOperationType> pendingOperations = repoShadow.asObjectable().getPendingOperation();
    if (pendingOperations.isEmpty()) {
        return resultShadow;
    }
    ShadowType resultShadowBean = resultShadow.asObjectable();
    List<PendingOperationType> sortedOperations = sortPendingOperations(pendingOperations);
    Duration gracePeriod = ProvisioningUtil.getGracePeriod(ctx);
    boolean resourceReadIsCachingOnly = ProvisioningUtil.resourceReadIsCachingOnly(ctx.getResource());
    for (PendingOperationType pendingOperation : sortedOperations) {
        OperationResultStatusType resultStatus = pendingOperation.getResultStatus();
        PendingOperationExecutionStatusType executionStatus = pendingOperation.getExecutionStatus();
        if (OperationResultStatusType.NOT_APPLICABLE.equals(resultStatus)) {
            // Not applicable means: "no point trying this, will not retry". Therefore it will not change future state.
            continue;
        }
        if (PendingOperationExecutionStatusType.COMPLETED.equals(executionStatus) && ProvisioningUtil.isOverPeriod(now, gracePeriod, pendingOperation)) {
            // Completed operations over grace period. They have already affected current state. They are already "applied".
            continue;
        }
        // are going to be retried and they still may influence future state
        if (skipExecutionPendingOperations && executionStatus == PendingOperationExecutionStatusType.EXECUTION_PENDING) {
            continue;
        }
        if (resourceReadIsCachingOnly) {
            // Re-applying them will mean additional risk of corrupting the data.
            if (resultStatus != null && resultStatus != OperationResultStatusType.IN_PROGRESS && resultStatus != OperationResultStatusType.UNKNOWN) {
                continue;
            }
        } else {
        // We want to apply all the deltas, even those that are already completed. They might not be reflected on the resource yet.
        // E.g. they may be not be present in the CSV export until the next export cycle is scheduled
        }
        ObjectDeltaType pendingDeltaType = pendingOperation.getDelta();
        ObjectDelta<ShadowType> pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext);
        if (pendingDelta.isAdd()) {
            // resource are going to be more precise than the pending ADD delta (which might not have been applied completely)
            if (resourceShadow == null) {
                ShadowType repoShadowBean = repoShadow.asObjectable();
                resultShadow = pendingDelta.getObjectToAdd().clone();
                resultShadow.setOid(repoShadow.getOid());
                resultShadowBean = resultShadow.asObjectable();
                resultShadowBean.setExists(true);
                resultShadowBean.setName(repoShadowBean.getName());
                resultShadowBean.setShadowLifecycleState(repoShadowBean.getShadowLifecycleState());
                List<PendingOperationType> newPendingOperations = resultShadowBean.getPendingOperation();
                for (PendingOperationType pendingOperation2 : repoShadowBean.getPendingOperation()) {
                    newPendingOperations.add(pendingOperation2.clone());
                }
                applyAttributesDefinition(ctx, resultShadow);
            }
        }
        if (pendingDelta.isModify()) {
            pendingDelta.applyTo(resultShadow);
        }
        if (pendingDelta.isDelete()) {
            resultShadowBean.setDead(true);
            resultShadowBean.setExists(false);
            resultShadowBean.setPrimaryIdentifierValue(null);
        }
    }
    // }
    return resultShadow;
}
Also used : ObjectDeltaType(com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType) Duration(javax.xml.datatype.Duration)

Example 43 with Duration

use of javax.xml.datatype.Duration in project midpoint by Evolveum.

the class TriggerAsserter method assertTimestampFuture.

public TriggerAsserter<R> assertTimestampFuture(XMLGregorianCalendar now, String durationOffset, long tolerance) {
    Duration offsetDuration = XmlTypeConverter.createDuration(durationOffset);
    XMLGregorianCalendar mid = XmlTypeConverter.addDuration(now, offsetDuration);
    XMLGregorianCalendar start = XmlTypeConverter.addMillis(mid, -tolerance);
    XMLGregorianCalendar end = XmlTypeConverter.addMillis(mid, tolerance);
    TestUtil.assertBetween("Wrong timestamp in " + desc(), start, end, trigger.getTimestamp());
    return this;
}
Also used : XMLGregorianCalendar(javax.xml.datatype.XMLGregorianCalendar) Duration(javax.xml.datatype.Duration)

Example 44 with Duration

use of javax.xml.datatype.Duration in project midpoint by Evolveum.

the class RefreshHelper method deleteDeadShadowIfPossible.

private PrismObject<ShadowType> deleteDeadShadowIfPossible(ProvisioningContext ctx, PrismObject<ShadowType> repoShadow, XMLGregorianCalendar now, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException {
    ShadowType shadowType = repoShadow.asObjectable();
    if (!ShadowUtil.isDead(shadowType)) {
        return repoShadow;
    }
    Duration gracePeriod = ProvisioningUtil.getGracePeriod(ctx);
    Duration deadRetentionPeriod = ProvisioningUtil.getDeadShadowRetentionPeriod(ctx);
    Duration expirationPeriod = XmlTypeConverter.longerDuration(gracePeriod, deadRetentionPeriod);
    XMLGregorianCalendar lastActivityTimestamp = null;
    for (PendingOperationType pendingOperation : shadowType.getPendingOperation()) {
        lastActivityTimestamp = XmlTypeConverter.laterTimestamp(lastActivityTimestamp, pendingOperation.getRequestTimestamp());
        lastActivityTimestamp = XmlTypeConverter.laterTimestamp(lastActivityTimestamp, pendingOperation.getLastAttemptTimestamp());
        lastActivityTimestamp = XmlTypeConverter.laterTimestamp(lastActivityTimestamp, pendingOperation.getCompletionTimestamp());
    }
    if (lastActivityTimestamp == null) {
        MetadataType metadata = shadowType.getMetadata();
        if (metadata != null) {
            lastActivityTimestamp = metadata.getModifyTimestamp();
            if (lastActivityTimestamp == null) {
                lastActivityTimestamp = metadata.getCreateTimestamp();
            }
        }
    }
    // If we have zero deadRetentionPeriod, we should get rid of all dead shadows immediately.
    if (XmlTypeConverter.isZero(deadRetentionPeriod) || expirationPeriod == null || lastActivityTimestamp == null || XmlTypeConverter.isAfterInterval(lastActivityTimestamp, expirationPeriod, now)) {
        // Perish you stinking corpse!
        LOGGER.debug("Deleting dead {} because it is expired", repoShadow);
        shadowManager.deleteShadow(repoShadow, task, parentResult);
        definitionsHelper.applyDefinition(repoShadow, task, parentResult);
        ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, repoShadow, repoShadow.createDeleteDelta(), parentResult);
        operationListener.notifySuccess(operationDescription, task, parentResult);
        return null;
    }
    LOGGER.trace("Keeping dead {} because it is not expired yet, last activity={}, expiration period={}", repoShadow, lastActivityTimestamp, expirationPeriod);
    return repoShadow;
}
Also used : XMLGregorianCalendar(javax.xml.datatype.XMLGregorianCalendar) ResourceOperationDescription(com.evolveum.midpoint.provisioning.api.ResourceOperationDescription) Duration(javax.xml.datatype.Duration)

Example 45 with Duration

use of javax.xml.datatype.Duration in project midpoint by Evolveum.

the class RefreshHelper method refreshShadowRetryOperations.

private RefreshShadowOperation refreshShadowRetryOperations(ProvisioningContext ctx, PrismObject<ShadowType> repoShadow, List<PendingOperationType> sortedOperations, ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, ExpressionEvaluationException, EncryptionException {
    ShadowType shadowType = repoShadow.asObjectable();
    OperationResult retryResult = new OperationResult(OP_REFRESH_RETRY);
    if (ShadowUtil.isDead(shadowType)) {
        RefreshShadowOperation rso = new RefreshShadowOperation();
        retryResult.recordSuccess();
        rso.setRefreshedShadow(repoShadow);
        rso.setRefreshResult(retryResult);
        return rso;
    }
    Duration retryPeriod = ProvisioningUtil.getRetryPeriod(ctx);
    Collection<ObjectDeltaOperation<ShadowType>> executedDeltas = new ArrayList<>();
    for (PendingOperationType pendingOperation : sortedOperations) {
        if (!needsRetry(pendingOperation)) {
            continue;
        }
        // We really want to get "now" here. Retrying operation may take some time. We want good timestamps that do not lie.
        XMLGregorianCalendar now = clock.currentTimeXMLGregorianCalendar();
        if (!isAfterRetryPeriod(pendingOperation, retryPeriod, now)) {
            if (PendingOperationTypeType.RETRY != pendingOperation.getType()) {
                continue;
            }
            if (!ProvisioningOperationOptions.isForceRetry(options)) {
                continue;
            }
        }
        LOGGER.trace("Going to retry operation {} on {}", pendingOperation, repoShadow);
        // Record attempt number and timestamp before the operation
        // TODO: later use this as an optimistic lock to make sure that two threads won't retry the operation at the same time
        // TODO: move to a better place
        ObjectDelta<ShadowType> shadowDelta = repoShadow.createModifyDelta();
        ItemPath containerPath = pendingOperation.asPrismContainerValue().getPath();
        int attemptNumber = pendingOperation.getAttemptNumber() + 1;
        PropertyDelta<Integer> attemptNumberDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_ATTEMPT_NUMBER));
        attemptNumberDelta.setRealValuesToReplace(attemptNumber);
        shadowDelta.addModification(attemptNumberDelta);
        PropertyDelta<XMLGregorianCalendar> lastAttemptTimestampDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_LAST_ATTEMPT_TIMESTAMP));
        lastAttemptTimestampDelta.setRealValuesToReplace(now);
        shadowDelta.addModification(lastAttemptTimestampDelta);
        PropertyDelta<OperationResultStatusType> resultStatusDelta = shadowDelta.createPropertyModification(containerPath.append(PendingOperationType.F_RESULT_STATUS));
        resultStatusDelta.setRealValuesToReplace(OperationResultStatusType.IN_PROGRESS);
        shadowDelta.addModification(resultStatusDelta);
        shadowManager.modifyShadowAttributes(ctx, repoShadow, shadowDelta.getModifications(), parentResult);
        shadowDelta.applyTo(repoShadow);
        ObjectDeltaType pendingDeltaType = pendingOperation.getDelta();
        ObjectDelta<ShadowType> pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext);
        ProvisioningOperationState<? extends AsynchronousOperationResult> opState = ProvisioningOperationState.fromPendingOperation(repoShadow, pendingOperation);
        LOGGER.debug("Retrying operation {} on {}, attempt #{}", pendingDelta, repoShadow, attemptNumber);
        ObjectDeltaOperation<ShadowType> objectDeltaOperation = new ObjectDeltaOperation<>(pendingDelta);
        OperationResult result = parentResult.createSubresult(OP_OPERATION_RETRY);
        try {
            retryOperation(ctx, pendingDelta, opState, task, result);
            repoShadow = opState.getRepoShadow();
            result.computeStatus();
            if (result.isError()) {
                retryResult.setStatus(result.getStatus());
            }
            // TODO maybe add whole "result" as subresult to the retryResult?
            result.muteError();
        } catch (CommunicationException | GenericFrameworkException | ObjectAlreadyExistsException | SchemaException | ObjectNotFoundException | ConfigurationException | SecurityViolationException e) {
            // This is final failure: the error is not handled.
            // Therefore the operation is now completed - finished with an error.
            // But we do not want to stop the task. Just log the error.
            LOGGER.error("Operation {} on {} ended up with an error after {} retries: {}", pendingDelta, repoShadow, attemptNumber, e.getMessage(), e);
            // The retry itself was a success. Operation that was retried might have failed.
            // And that is recorded in the shadow. But we have successfully retried the operation.
            result.recordHandledError(e);
            retryResult.recordFatalError("Operation " + pendingDelta + " on " + repoShadow + " ended with an error after " + attemptNumber + " retries: " + e.getMessage());
        } catch (Throwable e) {
            // This is unexpected error during retry. This means that there was other
            // failure that we did not expected. This is likely to be bug - or maybe wrong
            // error handling. This means that the retry was a failure.
            result.recordFatalError(e);
            retryResult.recordFatalError(e);
        } finally {
            // Status should be set by now, we just want to close the result
            result.computeStatusIfUnknown();
        }
        objectDeltaOperation.setExecutionResult(result);
        executedDeltas.add(objectDeltaOperation);
    }
    RefreshShadowOperation rso = new RefreshShadowOperation();
    rso.setExecutedDeltas(executedDeltas);
    rso.setRefreshedShadow(repoShadow);
    parentResult.computeStatus();
    rso.setRefreshResult(retryResult);
    LOGGER.trace("refreshShadowOperation {}", rso.debugDumpLazily());
    return rso;
}
Also used : ArrayList(java.util.ArrayList) OperationResult(com.evolveum.midpoint.schema.result.OperationResult) AsynchronousOperationResult(com.evolveum.midpoint.schema.result.AsynchronousOperationResult) GenericFrameworkException(com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException) RefreshShadowOperation(com.evolveum.midpoint.schema.RefreshShadowOperation) Duration(javax.xml.datatype.Duration) XMLGregorianCalendar(javax.xml.datatype.XMLGregorianCalendar) ObjectDeltaType(com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType) ObjectDeltaOperation(com.evolveum.midpoint.schema.ObjectDeltaOperation) ItemPath(com.evolveum.midpoint.prism.path.ItemPath)

Aggregations

Duration (javax.xml.datatype.Duration)110 XMLGregorianCalendar (javax.xml.datatype.XMLGregorianCalendar)50 Test (org.junit.Test)17 OperationResult (com.evolveum.midpoint.schema.result.OperationResult)12 ArrayList (java.util.ArrayList)11 ObjectDeltaType (com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType)8 GregorianCalendar (java.util.GregorianCalendar)8 ItemPath (com.evolveum.midpoint.prism.path.ItemPath)7 Date (java.util.Date)7 CleanupPolicyType (com.evolveum.midpoint.xml.ns._public.common.common_3.CleanupPolicyType)6 Calendar (java.util.Calendar)6 ItemDelta (com.evolveum.midpoint.prism.delta.ItemDelta)5 XSDayTimeDuration (org.eclipse.wst.xml.xpath2.processor.internal.types.XSDayTimeDuration)5 Collection (java.util.Collection)4 NodeValue (org.apache.jena.sparql.expr.NodeValue)4 NotNull (org.jetbrains.annotations.NotNull)4 PrismObject (com.evolveum.midpoint.prism.PrismObject)3 PolyString (com.evolveum.midpoint.prism.polystring.PolyString)3 ObjectQuery (com.evolveum.midpoint.prism.query.ObjectQuery)3 Task (com.evolveum.midpoint.task.api.Task)3