Skip to content

Commit

Permalink
Asynchronization: delete
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed Apr 16, 2017
1 parent 610381e commit 73eedd6
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 49 deletions.
Expand Up @@ -41,6 +41,7 @@
import com.evolveum.midpoint.schema.internals.InternalsConfig;
import com.evolveum.midpoint.schema.processor.*;
import com.evolveum.midpoint.schema.result.AsynchronousOperationQueryable;
import com.evolveum.midpoint.schema.result.AsynchronousOperationResult;
import com.evolveum.midpoint.schema.result.AsynchronousOperationReturnValue;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
Expand Down Expand Up @@ -92,8 +93,10 @@ public class ResourceObjectConverter {
public static final String OPERATION_MODIFY_ENTITLEMENT = DOT_CLASS + "modifyEntitlement";
private static final String OPERATION_ADD_RESOURCE_OBJECT = DOT_CLASS + "addResourceObject";
private static final String OPERATION_MODIFY_RESOURCE_OBJECT = DOT_CLASS + "modifyResourceObject";
private static final String OPERATION_DELETE_RESOURCE_OBJECT = DOT_CLASS + "deleteResourceObject";
private static final String OPERATION_REFRESH_OPERATION_STATUS = DOT_CLASS + "refreshOperationStatus";


@Autowired
private EntitlementConverter entitlementConverter;

Expand Down Expand Up @@ -309,11 +312,13 @@ public AsynchronousOperationReturnValue<PrismObject<ShadowType>> addResourceObje
return AsynchronousOperationReturnValue.wrap(shadow, result);
}

public void deleteResourceObject(ProvisioningContext ctx, PrismObject<ShadowType> shadow,
public AsynchronousOperationResult deleteResourceObject(ProvisioningContext ctx, PrismObject<ShadowType> shadow,
OperationProvisioningScriptsType scripts, OperationResult parentResult)
throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException,
SecurityViolationException {

OperationResult result = parentResult.createSubresult(OPERATION_DELETE_RESOURCE_OBJECT);

LOGGER.trace("Deleting resource object {}", shadow);

Collection<? extends ResourceAttribute<?>> identifiers = ShadowUtil
Expand All @@ -322,8 +327,10 @@ public void deleteResourceObject(ProvisioningContext ctx, PrismObject<ShadowType
if (ProvisioningUtil.isProtectedShadow(ctx.getObjectClassDefinition(), shadow, matchingRuleRegistry)) {
LOGGER.error("Attempt to delete protected resource object " + ctx.getObjectClassDefinition() + ": "
+ identifiers + "; ignoring the request");
throw new SecurityViolationException("Cannot delete protected resource object "
SecurityViolationException e = new SecurityViolationException("Cannot delete protected resource object "
+ ctx.getObjectClassDefinition() + ": " + identifiers);
result.recordFatalError(e);
throw e;
}

//check idetifier if it is not null
Expand All @@ -333,13 +340,13 @@ public void deleteResourceObject(ProvisioningContext ctx, PrismObject<ShadowType
}

// Execute entitlement modification on other objects (if needed)
executeEntitlementChangesDelete(ctx, shadow, scripts, parentResult);
executeEntitlementChangesDelete(ctx, shadow, scripts, result);

Collection<Operation> additionalOperations = new ArrayList<Operation>();
addExecuteScriptOperation(additionalOperations, ProvisioningOperationTypeType.DELETE, scripts, ctx.getResource(),
parentResult);
result);

ConnectorInstance connector = ctx.getConnector(parentResult);
ConnectorInstance connector = ctx.getConnector(result);
try {

if (LOGGER.isDebugEnabled()) {
Expand All @@ -351,35 +358,38 @@ public void deleteResourceObject(ProvisioningContext ctx, PrismObject<ShadowType
}

if (!ResourceTypeUtil.isDeleteCapabilityEnabled(ctx.getResource())){
throw new UnsupportedOperationException("Resource does not support 'delete' operation");
UnsupportedOperationException e = new UnsupportedOperationException("Resource does not support 'delete' operation");
result.recordFatalError(e);
throw e;
}

connector.deleteObject(ctx.getObjectClassDefinition(), additionalOperations, identifiers, ctx, parentResult);
connector.deleteObject(ctx.getObjectClassDefinition(), additionalOperations, identifiers, ctx, result);

computeResultStatus(parentResult);
LOGGER.debug("PROVISIONING DELETE: {}", parentResult.getStatus());
computeResultStatus(result);
LOGGER.debug("PROVISIONING DELETE: {}", result.getStatus());

} catch (ObjectNotFoundException ex) {
parentResult.recordFatalError("Can't delete object " + shadow
result.recordFatalError("Can't delete object " + shadow
+ ". Reason: " + ex.getMessage(), ex);
throw new ObjectNotFoundException("An error occured while deleting resource object " + shadow
+ "whith identifiers " + identifiers + ": " + ex.getMessage(), ex);
} catch (CommunicationException ex) {
parentResult.recordFatalError(
result.recordFatalError(
"Error communicating with the connector " + connector + ": " + ex.getMessage(), ex);
throw new CommunicationException("Error communicating with the connector " + connector + ": "
+ ex.getMessage(), ex);
} catch (ConfigurationException ex) {
parentResult.recordFatalError(
result.recordFatalError(
"Configuration error in connector " + connector + ": " + ex.getMessage(), ex);
throw new ConfigurationException("Configuration error in connector " + connector + ": "
+ ex.getMessage(), ex);
} catch (GenericFrameworkException ex) {
parentResult.recordFatalError("Generic error in connector: " + ex.getMessage(), ex);
result.recordFatalError("Generic error in connector: " + ex.getMessage(), ex);
throw new GenericConnectorException("Generic error in connector: " + ex.getMessage(), ex);
}

LOGGER.trace("Deleted resource object {}", shadow);
return AsynchronousOperationResult.wrap(result);
}

public AsynchronousOperationReturnValue<Collection<PropertyDelta<PrismPropertyValue>>> modifyResourceObject(
Expand Down
Expand Up @@ -43,6 +43,7 @@
import com.evolveum.midpoint.schema.internals.InternalMonitor;
import com.evolveum.midpoint.schema.internals.InternalsConfig;
import com.evolveum.midpoint.schema.processor.*;
import com.evolveum.midpoint.schema.result.AsynchronousOperationResult;
import com.evolveum.midpoint.schema.result.AsynchronousOperationReturnValue;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
Expand Down Expand Up @@ -574,7 +575,7 @@ public void deleteShadow(PrismObject<ShadowType> shadow, ProvisioningOperationOp
// although the resource does not exists..
if (ProvisioningOperationOptions.isForce(options)) {
parentResult.muteLastSubresultError();
getRepositoryService().deleteObject(ShadowType.class, shadow.getOid(), parentResult);
shadowManager.deleteShadow(ctx, shadow, null, parentResult);
parentResult.recordHandledError(
"Resource defined in shadow does not exists. Shadow was deleted from the repository.");
return;
Expand All @@ -587,11 +588,14 @@ public void deleteShadow(PrismObject<ShadowType> shadow, ProvisioningOperationOp

LOGGER.trace("Deleting object {} from the resource {}.", shadow, ctx.getResource());

AsynchronousOperationResult asyncReturnValue = null;
if (shadow.asObjectable().getFailedOperationType() == null
|| (shadow.asObjectable().getFailedOperationType() != null
&& FailedOperationTypeType.ADD != shadow.asObjectable().getFailedOperationType())) {
try {
resouceObjectConverter.deleteResourceObject(ctx, shadow, scripts, parentResult);

asyncReturnValue = resouceObjectConverter.deleteResourceObject(ctx, shadow, scripts, parentResult);

} catch (Exception ex) {
try {
handleError(ctx, ex, shadow, FailedOperation.DELETE, null,
Expand All @@ -605,20 +609,24 @@ public void deleteShadow(PrismObject<ShadowType> shadow, ProvisioningOperationOp

LOGGER.trace("Detele object with oid {} form repository.", shadow.getOid());
try {
getRepositoryService().deleteObject(ShadowType.class, shadow.getOid(), parentResult);
ObjectDelta<ShadowType> delta = ObjectDelta.createDeleteDelta(shadow.getCompileTimeClass(),
shadow.getOid(), prismContext);
ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, shadow,
delta, parentResult);
operationListener.notifySuccess(operationDescription, task, parentResult);
shadowManager.deleteShadow(ctx, shadow, asyncReturnValue.getOperationResult(), parentResult);
} catch (ObjectNotFoundException ex) {
parentResult.recordFatalError("Can't delete object " + shadow + ". Reason: " + ex.getMessage(),
ex);
throw new ObjectNotFoundException("An error occured while deleting resource object " + shadow
+ "whith identifiers " + shadow + ": " + ex.getMessage(), ex);
}

if (!asyncReturnValue.isInProgress()) {
ObjectDelta<ShadowType> delta = ObjectDelta.createDeleteDelta(shadow.getCompileTimeClass(),
shadow.getOid(), prismContext);
ResourceOperationDescription operationDescription = createSuccessOperationDescription(ctx, shadow,
delta, parentResult);
operationListener.notifySuccess(operationDescription, task, parentResult);
}

LOGGER.trace("Object deleted from repository successfully.");
parentResult.recordSuccess();
parentResult.computeStatus();
resourceManager.modifyResourceAvailabilityStatus(ctx.getResource().asPrismObject(),
AvailabilityStatusType.UP, parentResult);
}
Expand All @@ -640,14 +648,12 @@ public void refreshShadow(PrismObject<ShadowType> shadow, ProvisioningOperationO
}

List<PendingOperationType> sortedOperations = sortOperations(pendingOperations);
LOGGER.info("SHADOW:\n{}", shadow.debugDump(1));

boolean hasRecentlyCompletedOperation = false;
ObjectDelta<ShadowType> shadowDelta = shadow.createModifyDelta();
for (PendingOperationType pendingOperation: sortedOperations) {

ItemPath containerPath = pendingOperation.asPrismContainerValue().getPath();
LOGGER.info("CPATH: {}", containerPath);
OperationResultStatusType statusType = pendingOperation.getResultStatus();
XMLGregorianCalendar completionTimestamp = pendingOperation.getCompletionTimestamp();
XMLGregorianCalendar now = null;
Expand Down Expand Up @@ -679,32 +685,39 @@ public void refreshShadow(PrismObject<ShadowType> shadow, ProvisioningOperationO
PropertyDelta<OperationResultStatusType> statusDelta = shadowDelta.createPropertyModification(containerPath.subPath(PendingOperationType.F_RESULT_STATUS));
statusDelta.setValuesToReplace(new PrismPropertyValue<>(newStatusType));
shadowDelta.addModification(statusDelta);
statusType = newStatusType;
}

statusType = newStatusType;

if (operationCompleted) {
// Operation completed
PropertyDelta<XMLGregorianCalendar> timestampDelta = shadowDelta.createPropertyModification(containerPath.subPath(PendingOperationType.F_COMPLETION_TIMESTAMP));
timestampDelta.setValuesToReplace(new PrismPropertyValue<>(now));
shadowDelta.addModification(timestampDelta);
completionTimestamp = now;

if (operationCompleted) {
// Operation completed
PropertyDelta<Object> timestampDelta = shadowDelta.createPropertyModification(containerPath.subPath(PendingOperationType.F_COMPLETION_TIMESTAMP));
timestampDelta.setValuesToReplace(new PrismPropertyValue<>(now));
shadowDelta.addModification(timestampDelta);
completionTimestamp = now;

ObjectDeltaType pendingDeltaType = pendingOperation.getDelta();
ObjectDelta<ShadowType> pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext);

// We do not need to care about add deltas here. The add operation is already applied to
// attributes. We need this to "allocate" the identifiers, so iteration mechanism in the
// model can find unique values while taking pending create operations into consideration.

if (pendingDelta.isModify()) {
for (ItemDelta<?, ?> pendingModification: pendingDelta.getModifications()) {
shadowDelta.addModification(pendingModification.clone());
}
ObjectDeltaType pendingDeltaType = pendingOperation.getDelta();
ObjectDelta<ShadowType> pendingDelta = DeltaConvertor.createObjectDelta(pendingDeltaType, prismContext);

// We do not need to care about add deltas here. The add operation is already applied to
// attributes. We need this to "allocate" the identifiers, so iteration mechanism in the
// model can find unique values while taking pending create operations into consideration.

if (pendingDelta.isModify()) {
for (ItemDelta<?, ?> pendingModification: pendingDelta.getModifications()) {
shadowDelta.addModification(pendingModification.clone());
}

if (pendingDelta.isDelete()) {
// TODO: dead
}

if (pendingDelta.isDelete()) {
if (gracePeriod == null) {
shadowDelta = shadow.createDeleteDelta();
break;
} else {
PropertyDelta<Boolean> deadDelta = shadowDelta.createPropertyModification(new ItemPath(ShadowType.F_DEAD));
deadDelta.setValuesToReplace(new PrismPropertyValue<>(true));
shadowDelta.addModification(deadDelta);
}

}
}

Expand Down
Expand Up @@ -806,6 +806,21 @@ private void addPendingOperationModify(ProvisioningContext ctx, PrismObject<Shad
for (ItemDelta pendingModification: pendingModifications) {
pendingDelta.addModification(pendingModification.clone());
}

addPendingOperationDelta(ctx, shadow, pendingDelta, resourceOperationResult, parentResult);
}


private void addPendingOperationDelete(ProvisioningContext ctx, PrismObject<ShadowType> oldRepoShadow,
OperationResult resourceOperationResult, OperationResult parentResult) throws SchemaException, ObjectNotFoundException {

ObjectDelta<ShadowType> pendingDelta = oldRepoShadow.createDeleteDelta();

addPendingOperationDelta(ctx, oldRepoShadow, pendingDelta, resourceOperationResult, parentResult);
}

private void addPendingOperationDelta(ProvisioningContext ctx, PrismObject<ShadowType> shadow, ObjectDelta<ShadowType> pendingDelta,
OperationResult resourceOperationResult, OperationResult parentResult) throws SchemaException, ObjectNotFoundException {
ObjectDeltaType pendingDeltaType = DeltaConvertor.toObjectDeltaType(pendingDelta);

PendingOperationType pendingOperation = new PendingOperationType();
Expand All @@ -825,7 +840,6 @@ private void addPendingOperationModify(ProvisioningContext ctx, PrismObject<Shad
throw new SystemException(ex);
}
}


/**
* Create a copy of a shadow that is suitable for repository storage.
Expand Down Expand Up @@ -1207,6 +1221,15 @@ private <T> void compareUpdateProperty(ObjectDelta<ShadowType> shadowDelta,
shadowDelta.addModification(itemDelta);
}
}

public void deleteShadow(ProvisioningContext ctx, PrismObject<ShadowType> oldRepoShadow, OperationResult resourceOperationResult, OperationResult parentResult) throws ObjectNotFoundException, SchemaException {
LOGGER.trace("Deleting repository {}, resourceOperationResult={}", oldRepoShadow, resourceOperationResult.getStatus());
if (resourceOperationResult != null && resourceOperationResult.isInProgress()) {
addPendingOperationDelete(ctx, oldRepoShadow, resourceOperationResult, parentResult);
} else {
repositoryService.deleteObject(ShadowType.class, oldRepoShadow.getOid(), parentResult);
}
}

/**
* Re-reads the shadow, re-evaluates the identifiers and stored values, updates them if necessary. Returns
Expand Down

0 comments on commit 73eedd6

Please sign in to comment.