Skip to content

Commit

Permalink
Consistency update: fixing model-impl tests
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed Aug 13, 2018
1 parent 56d9026 commit ff776d9
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 57 deletions.
Expand Up @@ -30,15 +30,15 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType;

/**
* Aggregate bean containing resource OID, intent and thombstone flag.
* Aggregate bean containing resource OID, intent and tombstone flag.
* It uniquely identifies an shadow projection (usually account) for a specific user regardless whether it has OID, does not have
* OID yet, it exists of was deleted.
*
* This is used mostly as a key in hashes and for searches.
*
* TODO: split to two objects:
* 1: ResourceShadowCoordinates which will stay in common
* 2: ResourceShadowDiscriminator (subclass) which will go to model. This will contains thombstone and order.
* 2: ResourceShadowDiscriminator (subclass) which will go to model. This will contains tombstone and order.
*
* @author Radovan Semancik
*/
Expand All @@ -49,12 +49,12 @@ public class ResourceShadowDiscriminator implements Serializable, DebugDumpable,
private ShadowKindType kind = ShadowKindType.ACCOUNT;
private String intent;
private QName objectClass;
private boolean thombstone;
private boolean tombstone;
private int order = 0;

public ResourceShadowDiscriminator(String resourceOid, ShadowKindType kind, String intent, boolean thombstone) {
public ResourceShadowDiscriminator(String resourceOid, ShadowKindType kind, String intent, boolean tombstone) {
this.resourceOid = resourceOid;
this.thombstone = thombstone;
this.tombstone = tombstone;
setIntent(intent);
setKind(kind);
}
Expand All @@ -78,7 +78,7 @@ public ResourceShadowDiscriminator(ShadowDiscriminatorType accRefType, String de
} else {
this.resourceOid = accRefType.getResourceRef().getOid();
}
this.thombstone = false;
this.tombstone = false;
setIntent(accRefType.getIntent());
setKind(kind);
}
Expand Down Expand Up @@ -133,18 +133,18 @@ public void setOrder(int order) {
}

/**
* Thumbstone flag is true: the account no longer exists. The data we have are the latest metadata we were able to get.
* The projection will be marked as thombstone if we discover that the associated resource object is gone. Or the shadow
* is gone and we can no longer associate the resource object. In any way the thombstoned projection is marked for removal.
* Tombstone flag is true: the account no longer exists. The data we have are the latest metadata we were able to get.
* The projection will be marked as tombstone if we discover that the associated resource object is gone. Or the shadow
* is gone and we can no longer associate the resource object. In any way the tombstoned projection is marked for removal.
* It will be eventually unlinked and the shadow will be deleted. The shadow may stay around in the "dead" state for
* some time for reporting purposes.
*/
public boolean isThombstone() {
return thombstone;
public boolean isTombstone() {
return tombstone;
}

public void setThombstone(boolean thombstone) {
this.thombstone = thombstone;
public void setTombstone(boolean tombstone) {
this.tombstone = tombstone;
}

public boolean isWildcard() {
Expand Down Expand Up @@ -189,7 +189,7 @@ public int hashCode() {
result = prime * result + order;
result = prime * result
+ ((resourceOid == null) ? 0 : resourceOid.hashCode());
result = prime * result + (thombstone ? 1231 : 1237);
result = prime * result + (tombstone ? 1231 : 1237);
return result;
}

Expand All @@ -216,7 +216,7 @@ public boolean equals(Object obj) {
return false;
} else if (!resourceOid.equals(other.resourceOid))
return false;
if (thombstone != other.thombstone)
if (tombstone != other.tombstone)
return false;
return true;
}
Expand All @@ -242,7 +242,7 @@ public boolean equivalent(Object obj) {
return false;
} else if (!resourceOid.equals(other.resourceOid))
return false;
if (thombstone != other.thombstone)
if (tombstone != other.tombstone)
return false;
return true;
}
Expand Down Expand Up @@ -273,8 +273,8 @@ public String toHumanReadableDescription() {
sb.append(" order=");
sb.append(order);
}
if (thombstone) {
sb.append(" THOMBSTONE");
if (tombstone) {
sb.append(" TOMBSTONE");
}
sb.append(")");
return sb.toString();
Expand All @@ -289,7 +289,7 @@ public String debugDump(int indent) {
DebugUtil.debugDumpWithLabelToStringLn(sb, "kind", kind, indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "intent", indent, indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "objectClass", objectClass, indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "thombstone", thombstone, indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "tombstone", tombstone, indent + 1);
DebugUtil.debugDumpWithLabel(sb, "order", order, indent + 1);
return sb.toString();
}
Expand Down
Expand Up @@ -674,6 +674,10 @@ private <O extends ObjectType, F extends FocusType> void updateLinks(
}

private boolean linkShouldExist(LensProjectionContext projCtx, PrismObject<ShadowType> shadowAfterModification, OperationResult result) {
if (!projCtx.isShadowExistsInRepo()) {
// Nothing to link to
return false;
}
if (projCtx.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.UNLINK) {
return false;
}
Expand All @@ -696,7 +700,7 @@ private boolean linkShouldExist(LensProjectionContext projCtx, PrismObject<Shado
*/
private boolean isEmptyThombstone(LensProjectionContext projCtx) {
return projCtx.getResourceShadowDiscriminator() != null
&& projCtx.getResourceShadowDiscriminator().isThombstone()
&& projCtx.getResourceShadowDiscriminator().isTombstone()
&& projCtx.getObjectCurrent() == null;
}

Expand Down Expand Up @@ -809,8 +813,14 @@ private <F extends ObjectType> void updateSituationInShadow(Task task,
return;
}

SynchronizationSituationType currentSynchronizationSituation = currentShadow.asObjectable().getSynchronizationSituation();
if (SynchronizationSituationType.DELETED.equals(currentSynchronizationSituation) && ShadowUtil.isDead(currentShadow.asObjectable())) {
LOGGER.trace("Skipping update of synchronization situation for deleted dead shadow");
result.recordSuccess();
return;
}

// TODO: can we skip the update or cannot we? Do we always need to update sync timestamp?
// SynchronizationSituationType currentSynchronizationSituation = currentShadow.asObjectable().getSynchronizationSituation();
// if (newSituation.equals(currentSynchronizationSituation)) {
// LOGGER.trace("Skipping update of synchronization situation because there is no change ({})", currentSynchronizationSituation);
// result.recordSuccess();
Expand Down
Expand Up @@ -119,6 +119,13 @@ public class LensProjectionContext extends LensElementContext<ShadowType> implem
* isExists will in fact be true.
*/
private boolean isExists;

/**
* True if shadow exists in the repo. It is set to false after projector discovers that a shadow is gone.
* This is a corner case, but it may happen: if shadow is unintentionally deleted, if the shadow is
* cleaned up by another thread and so on.
*/
private transient boolean shadowExistsInRepo = true;

/**
* Decision regarding the account. It indicated what the engine has DECIDED TO DO with the context.
Expand Down Expand Up @@ -340,7 +347,7 @@ public boolean compareResourceShadowDiscriminator(ResourceShadowDiscriminator rs
if (!rsd.getKind().equals(resourceShadowDiscriminator.getKind())) {
return false;
}
if (rsd.isThombstone() != resourceShadowDiscriminator.isThombstone()) {
if (rsd.isTombstone() != resourceShadowDiscriminator.isTombstone()) {
return false;
}
if (rsd.getIntent() == null) {
Expand All @@ -366,7 +373,7 @@ public boolean isThombstone() {
if (resourceShadowDiscriminator == null) {
return false;
}
return resourceShadowDiscriminator.isThombstone();
return resourceShadowDiscriminator.isTombstone();
}

public void addAccountSyncDelta(ObjectDelta<ShadowType> delta) throws SchemaException {
Expand Down Expand Up @@ -483,6 +490,14 @@ public boolean isExists() {
public void setExists(boolean exists) {
this.isExists = exists;
}

public boolean isShadowExistsInRepo() {
return shadowExistsInRepo;
}

public void setShadowExistsInRepo(boolean shadowExistsInRepo) {
this.shadowExistsInRepo = shadowExistsInRepo;
}

public SynchronizationPolicyDecision getSynchronizationPolicyDecision() {
return synchronizationPolicyDecision;
Expand Down Expand Up @@ -931,7 +946,7 @@ public void checkConsistence(String contextDesc, boolean fresh, boolean force) {
if (synchronizationPolicyDecision == SynchronizationPolicyDecision.BROKEN) {
return;
}
if (fresh && !force && resourceShadowDiscriminator != null && !resourceShadowDiscriminator.isThombstone()) {
if (fresh && !force && resourceShadowDiscriminator != null && !resourceShadowDiscriminator.isTombstone()) {
if (resource == null) {
throw new IllegalStateException("Null resource in "+this + (contextDesc == null ? "" : " in " +contextDesc));
}
Expand Down Expand Up @@ -1220,6 +1235,9 @@ public String debugDump(int indent, boolean showTriples) {
sb.append(", shadow");
}
sb.append(", exists=").append(isExists);
if (!shadowExistsInRepo) {
sb.append(" (shadow not in repo)");
}
sb.append(", assigned=").append(isAssignedOld).append("->").append(isAssigned);
sb.append(", active=").append(isActive);
sb.append(", legal=").append(isLegalOld).append("->").append(isLegal);
Expand All @@ -1229,7 +1247,7 @@ public String debugDump(int indent, boolean showTriples) {
if (!isFresh()) {
sb.append(", NOT FRESH");
}
if (resourceShadowDiscriminator != null && resourceShadowDiscriminator.isThombstone()) {
if (resourceShadowDiscriminator != null && resourceShadowDiscriminator.isTombstone()) {
sb.append(", THOMBSTONE");
}
if (syncAbsoluteTrigger) {
Expand Down
Expand Up @@ -272,7 +272,7 @@ private <F extends ObjectType> void preprocessProjectionContext(LensContext<F> c
ResourceShadowDiscriminator rsd = projectionContext.getResourceShadowDiscriminator();
if (rsd != null) {
resourceOid = rsd.getResourceOid();
isThombstone = rsd.isThombstone();
isThombstone = rsd.isTombstone();
kind = rsd.getKind();
intent = rsd.getIntent();
order = rsd.getOrder();
Expand Down Expand Up @@ -532,9 +532,10 @@ private <F extends FocusType> void loadLinkRefsFromFocus(LensContext<F> context,
shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result);
} catch (ObjectNotFoundException e) {
// Broken accountRef. We need to mark it for deletion
LensProjectionContext accountContext = getOrCreateEmptyThombstoneProjectionContext(context, oid);
accountContext.setFresh(true);
accountContext.setExists(false);
LensProjectionContext projectionContext = getOrCreateEmptyThombstoneProjectionContext(context, oid);
projectionContext.setFresh(true);
projectionContext.setExists(false);
projectionContext.setShadowExistsInRepo(false);
OperationResult getObjectSubresult = result.getLastSubresult();
getObjectSubresult.setErrorsHandled();
continue;
Expand Down Expand Up @@ -675,6 +676,7 @@ private <F extends FocusType> void loadLinkRefsFromDelta(LensContext<F> context,
projectionContext.setPrimaryDelta(accountPrimaryDelta);
projectionContext.setFullShadow(true);
projectionContext.setExists(false);
projectionContext.setShadowExistsInRepo(false);
isCombinedAdd = true;
}
}
Expand Down Expand Up @@ -711,6 +713,7 @@ private <F extends FocusType> void loadLinkRefsFromDelta(LensContext<F> context,
projectionContext = getOrCreateEmptyThombstoneProjectionContext(context, oid);
projectionContext.setFresh(true);
projectionContext.setExists(false);
projectionContext.setShadowExistsInRepo(false);
OperationResult getObjectSubresult = result.getLastSubresult();
getObjectSubresult.setErrorsHandled();
} catch (ObjectNotFoundException ex){
Expand Down Expand Up @@ -795,6 +798,7 @@ private <F extends ObjectType> void loadProjectionContextsSync(LensContext<F> co
LOGGER.trace("Loading shadow {} from sync delta failed: not found", oid);
projCtx.setExists(false);
projCtx.setObjectCurrent(null);
projCtx.setShadowExistsInRepo(false);
}

// We will not set old account if the delta is delete. The
Expand All @@ -803,7 +807,7 @@ private <F extends ObjectType> void loadProjectionContextsSync(LensContext<F> co
// shadow)
if (syncDelta.getChangeType() == ChangeType.DELETE) {
projCtx.setExists(false);
projCtx.getResourceShadowDiscriminator().setThombstone(true);
projCtx.getResourceShadowDiscriminator().setTombstone(true);
} else if (shadow != null) {
syncDelta.applyTo(shadow);
projCtx.setLoadedObject(shadow);
Expand Down Expand Up @@ -885,17 +889,19 @@ private <F extends FocusType> LensProjectionContext getOrCreateAccountContext(Le
// This is somehow expected, fix it and we can go on
result.muteLastSubresultError();
// We have to create new context in this case, but it has to have thumbstone set
rsd.setThombstone(true);
rsd.setTombstone(true);
projectionContext = LensUtil.getOrCreateProjectionContext(context, rsd);
// We have to mark it as dead right now, otherwise the uniqueness check may fail
markShadowDead(projection.getOid(), result);
projectionContext.setShadowExistsInRepo(false);
}
} catch (ObjectNotFoundException e) {
// This is somehow expected, fix it and we can go on
result.muteLastSubresultError();
String shadowOid = projectionContext.getOid();
projectionContext.getResourceShadowDiscriminator().setThombstone(true);
projectionContext.getResourceShadowDiscriminator().setTombstone(true);
projectionContext = LensUtil.getOrCreateProjectionContext(context, rsd);
projectionContext.setShadowExistsInRepo(false);
// We have to mark it as dead right now, otherwise the uniqueness check may fail
markShadowDead(shadowOid, result);
}
Expand Down Expand Up @@ -968,7 +974,7 @@ private <F extends ObjectType> LensProjectionContext getOrCreateEmptyThombstoneP
if (projContext.getResourceShadowDiscriminator() == null) {
projContext.setResourceShadowDiscriminator(new ResourceShadowDiscriminator(null, null, null, true));
} else {
projContext.getResourceShadowDiscriminator().setThombstone(true);
projContext.getResourceShadowDiscriminator().setTombstone(true);
}

projContext.setFullShadow(false);
Expand Down Expand Up @@ -1077,6 +1083,7 @@ private <F extends ObjectType> void finishLoadOfProjectionContext(LensContext<F>
// Consistency mechanism might have kicked in and fixed the shadow.
// What we really want here is a thombstone projection or a refreshed projection.
result.muteLastSubresultError();
projContext.setShadowExistsInRepo(false);
refreshContextAfterShadowNotFound(context, projContext, options, task, result);

} catch (CommunicationException | SchemaException | ConfigurationException | SecurityViolationException
Expand Down Expand Up @@ -1155,7 +1162,7 @@ private <F extends ObjectType> void finishLoadOfProjectionContext(LensContext<F>
} else {
if (thombstone) {
// We do not want to reset thombstone flag if it was set before
discr.setThombstone(thombstone);
discr.setTombstone(thombstone);
}
}

Expand Down Expand Up @@ -1285,6 +1292,7 @@ public <F extends ObjectType> void loadFullShadow(LensContext<F> context, LensPr
} catch (ObjectNotFoundException ex) {
LOGGER.debug("Load of full resource object {} ended with ObjectNotFoundException (options={})", projCtx, getOptions);
result.muteLastSubresultError();
projCtx.setShadowExistsInRepo(false);
refreshContextAfterShadowNotFound(context, projCtx, options, task, result);
}

Expand Down Expand Up @@ -1355,8 +1363,10 @@ public <F extends ObjectType> void refreshContextAfterShadowNotFound(LensContext
}

if (!compensated) {
LOGGER.trace("ObjectNotFound error is not compensated, setting context to thombstone");
projCtx.getResourceShadowDiscriminator().setThombstone(true);
LOGGER.trace("ObjectNotFound error is not compensated, setting context to tombstone");
if (projCtx.getResourceShadowDiscriminator() != null) {
projCtx.getResourceShadowDiscriminator().setTombstone(true);
}
projCtx.setExists(false);
projCtx.setFullShadow(false);
}
Expand Down
Expand Up @@ -190,7 +190,7 @@ private <F extends ObjectType> LensProjectionContext determineProjectionWaveProv
// started, we checked at the beginning). Therefore this context must have been visited again.
// therefore there is a circular dependency. Therefore we need to create another context to split it.
ResourceShadowDiscriminator origDiscr = projectionContext.getResourceShadowDiscriminator();
ResourceShadowDiscriminator discr = new ResourceShadowDiscriminator(origDiscr.getResourceOid(), origDiscr.getKind(), origDiscr.getIntent(), origDiscr.isThombstone());
ResourceShadowDiscriminator discr = new ResourceShadowDiscriminator(origDiscr.getResourceOid(), origDiscr.getKind(), origDiscr.getIntent(), origDiscr.isTombstone());
discr.setOrder(determinedOrder);
if (!projectionContext.compareResourceShadowDiscriminator(discr, true)){
resultAccountContext = createAnotherContext(context, projectionContext, discr);
Expand Down Expand Up @@ -384,7 +384,7 @@ private <F extends ObjectType> LensProjectionContext createAnotherContext(LensCo
private <F extends ObjectType> LensProjectionContext createAnotherContext(LensContext<F> context, LensProjectionContext origProjectionContext,
int determinedOrder) throws PolicyViolationException {
ResourceShadowDiscriminator origDiscr = origProjectionContext.getResourceShadowDiscriminator();
ResourceShadowDiscriminator discr = new ResourceShadowDiscriminator(origDiscr.getResourceOid(), origDiscr.getKind(), origDiscr.getIntent(), origDiscr.isThombstone());
ResourceShadowDiscriminator discr = new ResourceShadowDiscriminator(origDiscr.getResourceOid(), origDiscr.getKind(), origDiscr.getIntent(), origDiscr.isTombstone());
discr.setOrder(determinedOrder);
LensProjectionContext otherCtx = createAnotherContext(context, origProjectionContext, discr);
return otherCtx;
Expand Down
Expand Up @@ -129,7 +129,7 @@ public void check(Task task, OperationResult result) throws SchemaException, Obj
LensProjectionContext foundContext = context.findProjectionContextByOid(conflictingShadowCandidate.getOid());
if (foundContext != null) {
if (foundContext.getResourceShadowDiscriminator() != null) {
if (foundContext.getResourceShadowDiscriminator().isThombstone()) {
if (foundContext.getResourceShadowDiscriminator().isTombstone()) {
violation = false;
}
LOGGER.trace("Comparing with account in other context resulted to violation confirmation of {}", violation);
Expand All @@ -154,7 +154,7 @@ public void check(Task task, OperationResult result) throws SchemaException, Obj
}
}
}
if (projectionContext.getResourceShadowDiscriminator() != null && projectionContext.getResourceShadowDiscriminator().isThombstone()) {
if (projectionContext.getResourceShadowDiscriminator() != null && projectionContext.getResourceShadowDiscriminator().isTombstone()) {
satisfiesConstraints = true;
} else {
satisfiesConstraints = false;
Expand Down

0 comments on commit ff776d9

Please sign in to comment.