use of com.evolveum.midpoint.provisioning.api.ResourceObjectShadowChangeDescription in project midpoint by Evolveum.
the class TestSynchronizationService method test210AddedGroupPirates.
@Test
public void test210AddedGroupPirates() throws Exception {
final String TEST_NAME = "test210AddedGroupPirates";
TestUtil.displayTestTile(this, TEST_NAME);
// GIVEN
Task task = taskManager.createTaskInstance(TestSynchronizationService.class.getName() + "." + TEST_NAME);
OperationResult result = task.getResult();
MockLensDebugListener mockListener = new MockLensDebugListener();
clockwork.setDebugListener(mockListener);
PrismObject<ShadowType> shadowPirates = repoAddObjectFromFile(SHADOW_PIRATES_DUMMY_FILE, result);
provisioningService.applyDefinition(shadowPirates, task, result);
assertNotNull("No oid in shadow", shadowPirates.getOid());
DummyGroup dummyGroup = new DummyGroup();
dummyGroup.setName(GROUP_PIRATES_DUMMY_NAME);
dummyGroup.setEnabled(true);
dummyGroup.addAttributeValues(DummyResourceContoller.DUMMY_GROUP_ATTRIBUTE_DESCRIPTION, "Scurvy Pirates");
getDummyResource().addGroup(dummyGroup);
ResourceObjectShadowChangeDescription change = new ResourceObjectShadowChangeDescription();
change.setCurrentShadow(shadowPirates);
change.setResource(getDummyResourceObject());
// WHEN
TestUtil.displayWhen(TEST_NAME);
synchronizationService.notifyChange(change, task, result);
// THEN
TestUtil.displayWhen(TEST_NAME);
result.computeStatus();
TestUtil.assertSuccess(result);
LensContext<UserType> context = mockListener.getLastSyncContext();
display("Resulting context (as seen by debug listener)", context);
assertNotNull("No resulting context (as seen by debug listener)", context);
assertNotNull("No focus primary delta", context.getFocusContext().getPrimaryDelta());
// assertNotNull("No focus secondary delta", context.getFocusContext().getSecondaryDelta());
assertFalse("No executed focus deltas", context.getFocusContext().getExecutedDeltas().isEmpty());
ObjectDelta<UserType> userSecondaryDelta = (ObjectDelta<UserType>) context.getFocusContext().getExecutedDeltas().iterator().next().getObjectDelta();
ResourceShadowDiscriminator rat = new ResourceShadowDiscriminator(getDummyResourceObject().getOid(), ShadowKindType.ENTITLEMENT, INTENT_GROUP);
LensProjectionContext projCtx = context.findProjectionContext(rat);
assertNotNull("No projection sync context for " + rat, projCtx);
assertEquals("Wrong detected situation in context", SynchronizationSituationType.UNMATCHED, projCtx.getSynchronizationSituationDetected());
assertEquals("Wrong resolved situation in context", SynchronizationSituationType.LINKED, projCtx.getSynchronizationSituationResolved());
PrismAsserts.assertNoDelta("Unexpected projection primary delta", projCtx.getPrimaryDelta());
//it this really expected?? delta was already executed, should we expect it in the secondary delta?
// assertNotNull("Missing account secondary delta", accCtx.getSecondaryDelta());
// assertIterationDelta(accCtx.getSecondaryDelta(), 0, "");
assertLinked(RoleType.class, context.getFocusContext().getOid(), shadowPirates.getOid());
PrismObject<ShadowType> shadow = getShadowModelNoFetch(shadowPirates.getOid());
assertIteration(shadow, 0, "");
assertSituation(shadow, SynchronizationSituationType.LINKED);
}
use of com.evolveum.midpoint.provisioning.api.ResourceObjectShadowChangeDescription in project midpoint by Evolveum.
the class ObjectNotFoundHandler method createResourceObjectShadowChangeDescription.
private ResourceObjectShadowChangeDescription createResourceObjectShadowChangeDescription(ShadowType shadow, OperationResult result) {
ResourceObjectShadowChangeDescription change = new ResourceObjectShadowChangeDescription();
ObjectDelta<ShadowType> objectDelta = new ObjectDelta<ShadowType>(ShadowType.class, ChangeType.DELETE, shadow.asPrismObject().getPrismContext());
objectDelta.setOid(shadow.getOid());
change.setObjectDelta(objectDelta);
change.setResource(shadow.getResource().asPrismObject());
ShadowType account = (ShadowType) shadow;
change.setOldShadow(account.asPrismObject());
change.setSourceChannel(QNameUtil.qNameToUri(SchemaConstants.CHANGE_CHANNEL_DISCOVERY));
return change;
}
use of com.evolveum.midpoint.provisioning.api.ResourceObjectShadowChangeDescription in project midpoint by Evolveum.
the class ObjectNotFoundHandler method handleError.
@Override
public <T extends ShadowType> T handleError(T shadow, FailedOperation op, Exception ex, boolean doDiscovery, boolean compensate, Task task, OperationResult parentResult) throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
if (!doDiscovery) {
parentResult.recordFatalError(ex);
if (ex instanceof ObjectNotFoundException) {
throw (ObjectNotFoundException) ex;
} else {
throw new ObjectNotFoundException(ex.getMessage(), ex);
}
}
OperationResult result = parentResult.createSubresult("com.evolveum.midpoint.provisioning.consistency.impl.ObjectNotFoundHandler.handleError." + op.name());
result.addParam("shadow", shadow);
result.addParam("currentOperation", op);
if (ex.getMessage() != null) {
result.addParam("exception", ex.getMessage());
}
LOGGER.trace("Start compensating object not found situation while execution operation: {}", op.name(), ex);
// Task task = taskManager.createTaskInstance();
ObjectDelta delta = null;
switch(op) {
case DELETE:
LOGGER.debug("DISCOVERY: cannot find object {}. The operation in progress is DELETE, therefore just deleting the shadow", shadow);
LOGGER.trace("Deleting shadow from the repository.");
for (OperationResult subResult : parentResult.getSubresults()) {
subResult.muteError();
}
try {
cacheRepositoryService.deleteObject(ShadowType.class, shadow.getOid(), result);
} catch (ObjectNotFoundException e) {
LOGGER.debug("Cannot delete {} in consistency compensation (discovery): {} - this is probably harmless", shadow, e.getMessage());
}
String message = "Object was not found on the " + ObjectTypeUtil.toShortString(shadow.getResource()) + ". Shadow deleted from the repository to equalize the state on the resource and in the repository.";
parentResult.recordHandledError(message);
LOGGER.trace("Shadow deleted from the repository. Inconsistencies are now removed.");
result.computeStatus();
// parentResult status can be recomputed by the caller method
result.setStatus(OperationResultStatus.HANDLED_ERROR);
delta = ObjectDelta.createDeleteDelta(shadow.getClass(), shadow.getOid(), prismContext);
ResourceOperationDescription operationDescritpion = createOperationDescription(shadow, ex, shadow.getResource(), delta, task, result);
changeNotificationDispatcher.notifySuccess(operationDescritpion, task, result);
LOGGER.debug("DISCOVERY: cannot find object {}: DELETE operation handler done", shadow);
return shadow;
case MODIFY:
LOGGER.debug("DISCOVERY: cannot find object {}. The operation in progress is MODIFY, therefore initiating synchronization", shadow);
LOGGER.trace("Starting discovery to find out if the object should exist or not.");
OperationResult handleErrorResult = result.createSubresult("com.evolveum.midpoint.provisioning.consistency.impl.ObjectNotFoundHandler.handleError.discovery");
handleErrorResult.addContext(OperationResult.CONTEXT_RESOURCE, shadow.getResource());
ObjectDeltaType shadowModifications = shadow.getObjectChange();
Collection<? extends ItemDelta> modifications = DeltaConvertor.toModifications(shadowModifications.getItemDelta(), shadow.asPrismObject().getDefinition());
shadow.setDead(true);
Collection<? extends ItemDelta> deadDeltas = PropertyDelta.createModificationReplacePropertyCollection(ShadowType.F_DEAD, shadow.asPrismObject().getDefinition(), true);
ConstraintsChecker.onShadowModifyOperation(deadDeltas);
cacheRepositoryService.modifyObject(ShadowType.class, shadow.getOid(), deadDeltas, result);
ResourceObjectShadowChangeDescription change = createResourceObjectShadowChangeDescription(shadow, result);
try {
changeNotificationDispatcher.notifyChange(change, task, handleErrorResult);
} catch (RuntimeException e) {
handleErrorResult.recordFatalError(e);
result.computeStatus();
throw e;
}
handleErrorResult.computeStatus();
String oidVal = null;
String oid = findCreatedAccountOid(handleErrorResult, oidVal);
if (oid != null) {
LOGGER.trace("Found new oid {} as a return param from model. Probably the new shadow was created.", oid);
LOGGER.debug("DISCOVERY: object {} re-created, applying pending changes", shadow);
LOGGER.trace("Modifying re-created object by applying pending changes:\n{}", DebugUtil.debugDump(modifications));
try {
ProvisioningOperationOptions options = new ProvisioningOperationOptions();
options.setCompletePostponed(false);
options.setDoNotDiscovery(true);
provisioningService.modifyObject(ShadowType.class, oid, modifications, null, options, task, result);
parentResult.recordHandledError("Object was recreated and modifications were applied to newly created object.");
} catch (ObjectNotFoundException e) {
parentResult.recordHandledError("Modifications were not applied, because shadow was deleted by discovery. Repository state were refreshed and unused shadow was deleted.");
}
} else {
LOGGER.debug("DISCOVERY: object {} deleted, application of pending changes skipped", shadow);
parentResult.recordHandledError("Object was deleted by discovery. Modification were not applied.");
}
// We do not need the old shadow any more. Even if the object was re-created it has a new shadow now.
try {
cacheRepositoryService.deleteObject(ShadowType.class, shadow.getOid(), parentResult);
} catch (ObjectNotFoundException e) {
// delete the old shadow that was probably deleted from the
// user, or the new one was assigned
LOGGER.debug("Cannot delete {} in consistency compensation (discovery): {} - this is probably harmless", shadow, e.getMessage());
}
result.computeStatus();
if (parentResult.isHandledError()) {
// Ugly hack. We shouldn't set parentResult status in the first place, as it can be overriden by computeStatus/recomputeStatus called in the parent.
result.setStatus(OperationResultStatus.HANDLED_ERROR);
}
if (oid != null) {
shadowModifications.setOid(oid);
shadow.setOid(oid);
}
LOGGER.debug("DISCOVERY: cannot find object {}: MODIFY operation handler done", shadow);
return shadow;
case GET:
if (!compensate) {
LOGGER.trace("DISCOVERY: cannot find object {}, GET operation: handling skipped because discovery is disabled", shadow);
result.recordFatalError(ex.getMessage(), ex);
throw new ObjectNotFoundException(ex.getMessage(), ex);
}
LOGGER.debug("DISCOVERY: cannot find object {}. The operation in progress is GET, therefore initiating synchronization", shadow);
OperationResult handleGetErrorResult = result.createSubresult("com.evolveum.midpoint.provisioning.consistency.impl.ObjectNotFoundHandler.handleError.discovery");
handleGetErrorResult.addContext(OperationResult.CONTEXT_RESOURCE, shadow.getResource());
Collection<? extends ItemDelta> deadModification = PropertyDelta.createModificationReplacePropertyCollection(ShadowType.F_DEAD, shadow.asPrismObject().getDefinition(), true);
ConstraintsChecker.onShadowModifyOperation(deadModification);
try {
cacheRepositoryService.modifyObject(ShadowType.class, shadow.getOid(), deadModification, result);
} catch (ObjectNotFoundException e) {
// The shadow is not there. So we cannot mark it as dead.
LOGGER.debug("Cannot modify shadow {} in consistency compensation (discovery): {} - this is probably harmless", shadow, e.getMessage());
}
shadow.setDead(true);
ResourceObjectShadowChangeDescription getChange = createResourceObjectShadowChangeDescription(shadow, result);
if (task == null) {
task = taskManager.createTaskInstance();
}
try {
changeNotificationDispatcher.notifyChange(getChange, task, handleGetErrorResult);
} catch (RuntimeException e) {
LOGGER.trace("DISCOVERY: synchronization invoked for {} ended with an error {}", shadow, e);
handleGetErrorResult.recordFatalError(e);
result.computeStatus();
throw e;
}
// String oidVal = null;
handleGetErrorResult.computeStatus();
LOGGER.trace("DISCOVERY: synchronization invoked for {} finished with status {}", shadow, handleGetErrorResult.getStatus());
oid = findCreatedAccountOid(handleGetErrorResult, null);
try {
LOGGER.trace("DISCOVERY: deleting {}", shadow);
cacheRepositoryService.deleteObject(ShadowType.class, shadow.getOid(), result);
} catch (ObjectNotFoundException e) {
// delete the old shadow that was probably deleted from the
// user, or the new one was assigned
LOGGER.debug("Cannot delete {} in consistency compensation (discovery): {} - this is probably harmless", shadow, e.getMessage());
}
for (OperationResult subResult : parentResult.getSubresults()) {
subResult.muteError();
}
if (oid != null) {
PrismObject newShadow;
try {
LOGGER.trace("DISCOVERY: retrieving shadow {}", oid);
Collection<SelectorOptions<GetOperationOptions>> options = SelectorOptions.createCollection(GetOperationOptions.createDoNotDiscovery());
newShadow = provisioningService.getObject(shadow.getClass(), oid, options, task, result);
LOGGER.trace("DISCOVERY: retrieved {}", newShadow);
} catch (ObjectNotFoundException e) {
String msg = "Strange thing did happen: new shadow (" + oid + ") was supposedly created for old shadow " + shadow + ", however the new shadow was not found: " + e.getMessage();
LOGGER.error(msg);
result.recordFatalError(msg, e);
parentResult.recordFatalError(msg);
throw new ObjectNotFoundException(msg, ex);
} finally {
result.computeStatus();
}
LOGGER.debug("DISCOVERY: object {} re-created as {}. GET operation handler done: returning new shadow", shadow, newShadow);
shadow = (T) newShadow.asObjectable();
parentResult.recordHandledError("Object was re-created by the discovery.");
// parentResult status can be recomputed by the caller method
result.setStatus(OperationResultStatus.HANDLED_ERROR);
return shadow;
} else {
parentResult.recordHandledError("Object was deleted by the discovery and the invalid link was removed from the user.");
result.computeStatus();
// parentResult status can be recomputed by the caller method
result.setStatus(OperationResultStatus.HANDLED_ERROR);
LOGGER.debug("DISCOVERY: object {} was deleted. GET operation handler done: throwing ObjectNotFoundException", shadow);
throw new ObjectNotFoundException(ex.getMessage(), ex);
}
default:
throw new ObjectNotFoundException(ex.getMessage(), ex);
}
}
use of com.evolveum.midpoint.provisioning.api.ResourceObjectShadowChangeDescription in project midpoint by Evolveum.
the class TestSynchronization method test100SyncAddWill.
@Test
public void test100SyncAddWill() throws Exception {
final String TEST_NAME = "test100SyncAddWill";
TestUtil.displayTestTile(TEST_NAME);
final OperationResult result = new OperationResult(TestSynchronization.class.getName() + "." + TEST_NAME);
Task syncTask = taskManager.getTask(SYNC_TASK_OID, result);
AssertJUnit.assertNotNull(syncTask);
assertSyncToken(syncTask, 0, result);
((SynchornizationServiceMock) syncServiceMock).reset();
// create add change in embeded LDAP
LDIFImportConfig importConfig = new LDIFImportConfig(LDIF_WILL_FILE.getPath());
LDIFReader ldifReader = new LDIFReader(importConfig);
Entry entry = ldifReader.readEntry();
display("Entry from LDIF", entry);
AddOperation addOperation = openDJController.getInternalConnection().processAdd(entry);
AssertJUnit.assertEquals("LDAP add operation failed", ResultCode.SUCCESS, addOperation.getResultCode());
ResourceShadowDiscriminator coords = new ResourceShadowDiscriminator(resourceType.getOid(), AbstractOpenDjTest.RESOURCE_OPENDJ_ACCOUNT_OBJECTCLASS);
// WHEN
provisioningService.synchronize(coords, syncTask, result);
// THEN
SynchornizationServiceMock mock = (SynchornizationServiceMock) syncServiceMock;
assertEquals("Unexpected number of synchronization service calls", 1, mock.getCallCount());
ResourceObjectShadowChangeDescription lastChange = mock.getLastChange();
// ObjectDelta<? extends ShadowType> objectDelta = lastChange.getObjectDelta();
// assertNotNull("Null object delta in change notification", objectDelta);
// assertEquals("Wrong change type in delta in change notification", ChangeType.ADD, objectDelta.getChangeType());
PrismObject<? extends ShadowType> currentShadow = lastChange.getCurrentShadow();
assertNotNull("No current shadow in change notification", currentShadow);
assertNotNull("No old shadow in change notification", lastChange.getOldShadow());
assertEquals("Wrong shadow name", PrismTestUtil.createPolyStringType(ACCOUNT_WILL_NAME), currentShadow.asObjectable().getName());
assertSyncToken(SYNC_TASK_OID, 1, result);
}
use of com.evolveum.midpoint.provisioning.api.ResourceObjectShadowChangeDescription in project midpoint by Evolveum.
the class SynchronizeAccountResultHandler method handleObjectInternal.
protected boolean handleObjectInternal(PrismObject<ShadowType> accountShadow, Task workerTask, OperationResult result) {
ShadowType newShadowType = accountShadow.asObjectable();
if (newShadowType.isProtectedObject() != null && newShadowType.isProtectedObject()) {
LOGGER.trace("{} skipping {} because it is protected", new Object[] { getProcessShortNameCapitalized(), accountShadow });
result.recordStatus(OperationResultStatus.NOT_APPLICABLE, "Skipped because it is protected");
return true;
}
if (objectClass != null && (objectClass instanceof RefinedObjectClassDefinition) && !((RefinedObjectClassDefinition) objectClass).matches(newShadowType)) {
LOGGER.trace("{} skipping {} because it does not match objectClass/kind/intent", new Object[] { getProcessShortNameCapitalized(), accountShadow });
result.recordStatus(OperationResultStatus.NOT_APPLICABLE, "Skipped because it does not match objectClass/kind/intent");
return true;
}
if (objectChangeListener == null) {
LOGGER.warn("No object change listener set for {} task, ending the task", getProcessShortName());
result.recordFatalError("No object change listener set for " + getProcessShortName() + " task, ending the task");
return false;
}
// We are going to pretend that all of the objects were just created.
// That will efficiently import them to the IDM repository
ResourceObjectShadowChangeDescription change = new ResourceObjectShadowChangeDescription();
change.setSourceChannel(QNameUtil.qNameToUri(sourceChannel));
change.setResource(getResourceWorkingCopy().asPrismObject());
if (forceAdd) {
// We should provide shadow in the state before the change. But we are
// pretending that it has
// not existed before, so we will not provide it.
ObjectDelta<ShadowType> shadowDelta = new ObjectDelta<ShadowType>(ShadowType.class, ChangeType.ADD, accountShadow.getPrismContext());
//PrismObject<AccountShadowType> shadowToAdd = refinedAccountDefinition.getObjectDefinition().parseObjectType(newShadowType);
PrismObject<ShadowType> shadowToAdd = newShadowType.asPrismObject();
shadowDelta.setObjectToAdd(shadowToAdd);
shadowDelta.setOid(newShadowType.getOid());
change.setObjectDelta(shadowDelta);
// Need to also set current shadow. This will get reflected in "old" object in lens context
change.setCurrentShadow(accountShadow);
} else {
// No change, therefore the delta stays null. But we will set the current
change.setCurrentShadow(accountShadow);
}
try {
change.checkConsistence();
} catch (RuntimeException ex) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Check consistence failed: {}\nChange:\n{}", ex, change.debugDump());
}
throw ex;
}
// Invoke the change notification
Utils.clearRequestee(workerTask);
objectChangeListener.notifyChange(change, workerTask, result);
return workerTask.canRun();
}
Aggregations