Skip to content

Commit

Permalink
Fixing dependencies between object types on the same resource (MID-1841)
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed Jul 15, 2014
1 parent 1cd83bc commit 1a93713
Show file tree
Hide file tree
Showing 9 changed files with 265 additions and 43 deletions.
Expand Up @@ -58,12 +58,16 @@ public ResourceShadowDiscriminator(ShadowDiscriminatorType accRefType) {
this(accRefType.getResourceRef().getOid(), accRefType.getKind(), accRefType.getIntent());
}

public ResourceShadowDiscriminator(ShadowDiscriminatorType accRefType, ShadowKindType defaultKind) {
public ResourceShadowDiscriminator(ShadowDiscriminatorType accRefType, String defaultResourceOid, ShadowKindType defaultKind) {
ShadowKindType kind = accRefType.getKind();
if (kind == null) {
kind = defaultKind;
}
this.resourceOid = accRefType.getResourceRef().getOid();
if (accRefType.getResourceRef() == null) {
this.resourceOid = defaultResourceOid;
} else {
this.resourceOid = accRefType.getResourceRef().getOid();
}
this.thombstone = false;
setIntent(accRefType.getIntent());
setKind(kind);
Expand Down
Expand Up @@ -318,7 +318,7 @@ private <F extends ObjectType> void loadObjectCurrent(LensContext<F> context, Op
return;
}
ObjectDelta<F> objectDelta = focusContext.getDelta();
if (objectDelta != null && objectDelta.isAdd()) {
if (objectDelta != null && objectDelta.isAdd() && focusContext.getExecutedDeltas().isEmpty()) {
//we're adding the focal object. No need to load it, it is in the delta
focusContext.setFresh(true);
return;
Expand Down
Expand Up @@ -391,7 +391,8 @@ private <F extends ObjectType> LensProjectionContext determineProjectionWave(Len
}
checkForCircular(depPath, outDependency);
depPath.add(outDependency);
ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(outDependency, projectionContext.getKind());
ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(outDependency,
projectionContext.getResource().getOid(), projectionContext.getKind());
LensProjectionContext dependencyProjectionContext = findDependencyContext(context, projectionContext, outDependency);
// if (LOGGER.isTraceEnabled()) {
// LOGGER.trace("DEP: {} -> {}", refDiscr, dependencyProjectionContext);
Expand Down Expand Up @@ -473,7 +474,8 @@ private boolean isHigerOrder(ResourceObjectTypeDependencyType a,
*/
private <F extends ObjectType> LensProjectionContext findDependencyContext(
LensContext<F> context, LensProjectionContext projContext, ResourceObjectTypeDependencyType dependency){
ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(dependency, projContext.getKind());
ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(dependency,
projContext.getResource().getOid(), projContext.getKind());
LensProjectionContext selected = null;
for (LensProjectionContext projectionContext: context.getProjectionContexts()) {
if (!projectionContext.compareResourceShadowDiscriminator(refDiscr, false)) {
Expand Down Expand Up @@ -511,21 +513,21 @@ private <F extends ObjectType> LensProjectionContext createAnotherContext(LensCo
* and stuff like that.
*/
private <F extends ObjectType> boolean checkDependencies(LensContext<F> context,
LensProjectionContext accountContext) throws PolicyViolationException {
if (accountContext.isDelete()) {
LensProjectionContext projContext) throws PolicyViolationException {
if (projContext.isDelete()) {
// It is OK if we depend on something that is not there if we are being removed ... for now
return true;
}

if (accountContext.getOid() == null || accountContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD) {
if (projContext.getOid() == null || projContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD) {
// Check for lower-order contexts
LensProjectionContext lowerOrderContext = null;
for (LensProjectionContext projectionContext: context.getProjectionContexts()) {
if (accountContext == projectionContext) {
if (projContext == projectionContext) {
continue;
}
if (projectionContext.compareResourceShadowDiscriminator(accountContext.getResourceShadowDiscriminator(), false) &&
projectionContext.getResourceShadowDiscriminator().getOrder() < accountContext.getResourceShadowDiscriminator().getOrder()) {
if (projectionContext.compareResourceShadowDiscriminator(projContext.getResourceShadowDiscriminator(), false) &&
projectionContext.getResourceShadowDiscriminator().getOrder() < projContext.getResourceShadowDiscriminator().getOrder()) {
if (projectionContext.getOid() != null) {
lowerOrderContext = projectionContext;
break;
Expand All @@ -534,41 +536,42 @@ private <F extends ObjectType> boolean checkDependencies(LensContext<F> context,
}
if (lowerOrderContext != null) {
if (lowerOrderContext.getOid() != null) {
if (accountContext.getOid() == null) {
accountContext.setOid(lowerOrderContext.getOid());
if (projContext.getOid() == null) {
projContext.setOid(lowerOrderContext.getOid());
}
if (accountContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD) {
if (projContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD) {
// This context cannot be ADD. There is a lower-order context with an OID
// it means that the lower-order projection exists, we cannot add it twice
accountContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.KEEP);
projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.KEEP);
}
}
if (lowerOrderContext.isDelete()) {
accountContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.DELETE);
projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.DELETE);
}
}
}

for (ResourceObjectTypeDependencyType dependency: accountContext.getDependencies()) {
ResourceShadowDiscriminator refRat = new ResourceShadowDiscriminator(dependency, accountContext.getKind());
for (ResourceObjectTypeDependencyType dependency: projContext.getDependencies()) {
ResourceShadowDiscriminator refRat = new ResourceShadowDiscriminator(dependency,
projContext.getResource().getOid(), projContext.getKind());
LOGGER.trace("LOOKING FOR {}", refRat);
LensProjectionContext dependencyAccountContext = context.findProjectionContext(refRat);
ResourceObjectTypeDependencyStrictnessType strictness = ResourceTypeUtil.getDependencyStrictness(dependency);
if (dependencyAccountContext == null) {
if (strictness == ResourceObjectTypeDependencyStrictnessType.STRICT) {
// This should not happen, it is checked before projection
throw new PolicyViolationException("Unsatisfied strict dependency of "
+ accountContext.getResourceShadowDiscriminator().toHumanReadableString() +
+ projContext.getResourceShadowDiscriminator().toHumanReadableString() +
" dependent on " + refRat.toHumanReadableString() + ": No context in dependency check");
} else if (strictness == ResourceObjectTypeDependencyStrictnessType.LAX) {
// independent object not in the context, just ignore it
LOGGER.trace("Unsatisfied lax dependency of account " +
accountContext.getResourceShadowDiscriminator().toHumanReadableString() +
projContext.getResourceShadowDiscriminator().toHumanReadableString() +
" dependent on " + refRat.toHumanReadableString() + "; dependency skipped");
} else if (strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) {
// independent object not in the context, just ignore it
LOGGER.trace("Unsatisfied relaxed dependency of account "
+ accountContext.getResourceShadowDiscriminator().toHumanReadableString() +
+ projContext.getResourceShadowDiscriminator().toHumanReadableString() +
" dependent on " + refRat.toHumanReadableString() + "; dependency skipped");
} else {
throw new IllegalArgumentException("Unknown dependency strictness "+dependency.getStrictness()+" in "+refRat);
Expand All @@ -582,9 +585,9 @@ private <F extends ObjectType> boolean checkDependencies(LensContext<F> context,
} else {
// We do not want to throw exception here. That will stop entire projection.
// Let's just mark the projection as broken and skip it.
LOGGER.warn("Unsatisfied dependency of account "+accountContext.getResourceShadowDiscriminator()+
" dependent on "+refRat+": Account not provisioned in dependency check (execution wave "+context.getExecutionWave()+", account wave "+accountContext.getWave() + ", depenedency account wave "+dependencyAccountContext.getWave()+")");
accountContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.BROKEN);
LOGGER.warn("Unsatisfied dependency of account "+projContext.getResourceShadowDiscriminator()+
" dependent on "+refRat+": Account not provisioned in dependency check (execution wave "+context.getExecutionWave()+", account wave "+projContext.getWave() + ", depenedency account wave "+dependencyAccountContext.getWave()+")");
projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.BROKEN);
return false;
}
} else if (strictness == ResourceObjectTypeDependencyStrictnessType.LAX) {
Expand Down
Expand Up @@ -51,6 +51,7 @@
import com.evolveum.icf.dummy.resource.DummyObjectClass;
import com.evolveum.icf.dummy.resource.DummyResource;
import com.evolveum.icf.dummy.resource.DummySyncStyle;
import com.evolveum.midpoint.common.InternalsConfig;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchema;
import com.evolveum.midpoint.common.refinery.ShadowDiscriminatorObjectDelta;
Expand Down Expand Up @@ -162,6 +163,9 @@ public class TestVillage extends AbstractStoryTest {
public static final File ROLE_META_FUNCTIONAL_ORG_FILE = new File(TEST_DIR, "role-meta-functional-org.xml");
public static final String ROLE_META_FUNCTIONAL_ORG_OID = "74aac2c8-ca0f-11e3-bb29-001e8c717e5b";

public static final File ROLE_META_PROJECT_ORG_FILE = new File(TEST_DIR, "role-meta-project-org.xml");
public static final String ROLE_META_PROJECT_ORG_OID = "ab33ec1e-0c0b-11e4-ba88-001e8c717e5b";

protected static final File ORGS_FILE = new File(TEST_DIR, "orgs.xml");
public static final String ORG_GOV_NAME = "Gov";
public static final String ORG_EXEC_NAME = "Exec";
Expand All @@ -173,6 +177,9 @@ public class TestVillage extends AbstractStoryTest {
private static final File GLOBAL_PASSWORD_POLICY_FILE = new File(TEST_DIR, "global-password-policy.xml");
private static final File ORG_PASSWORD_POLICY_FILE = new File(TEST_DIR, "org-password-policy.xml");

public static final File ORG_PROJECT_JOLLY_ROGER_FILE = new File(TEST_DIR, "org-project-jolly-roger.xml");
public static final String ORG_PROJECT_JOLLY_ROGER_OID = "a9ac1aa2-0c0f-11e4-9214-001e8c717e5b";

protected static final File TASK_LIVE_SYNC_DUMMY_SOURCE_FILE = new File(TEST_DIR, "task-dumy-source-livesync.xml");
protected static final String TASK_LIVE_SYNC_DUMMY_SOURCE_OID = "10000000-0000-0000-5555-555500000001";

Expand Down Expand Up @@ -290,6 +297,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti
importObjectFromFile(ROLE_BASIC_FILE, initResult);
importObjectFromFile(ROLE_SIMPLE_FILE, initResult);
importObjectFromFile(ROLE_META_FUNCTIONAL_ORG_FILE, initResult);
importObjectFromFile(ROLE_META_PROJECT_ORG_FILE, initResult);

// Org
repoAddObjectsFromFile(ORGS_FILE, OrgType.class, initResult);
Expand Down Expand Up @@ -602,10 +610,12 @@ public void test132ModifySrcAccountHermanDeleteOrg() throws Exception {
DummyAccount account = dummyResourceSrc.getAccountByUsername(ACCOUNT_HERMAN_USERNAME);

// WHEN
TestUtil.displayWhen(TEST_NAME);
account.replaceAttributeValues(DUMMY_ACCOUNT_ATTRIBUTE_SRC_ORG);
waitForTaskNextRun(TASK_LIVE_SYNC_DUMMY_SOURCE_OID, true);

// THEN
TestUtil.displayThen(TEST_NAME);
PrismObject<UserType> user = findUserByUsername(getUsername(ACCOUNT_HERMAN_FIST_NAME, ACCOUNT_HERMAN_LAST_NAME, null));
assertUserNoRole(user, ACCOUNT_HERMAN_FIST_NAME, ACCOUNT_HERMAN_LAST_NAME, null);
assertLocGov(user, null, null);
Expand Down Expand Up @@ -633,9 +643,11 @@ public void test200createUserAssignOrgPwdPolicy() throws Exception{
Collection deltas = MiscUtil.createCollection(orgPasswordPolicyRefDelta);
modelService.executeChanges(deltas, null, task, result);

InternalsConfig.avoidLoggingChange = true;
ObjectDelta sysConfigPasswordPolicyRefDelta = ObjectDelta.createModificationAddReference(SystemConfigurationType.class, SYSTEM_CONFIGURATION_OID, SystemConfigurationType.F_GLOBAL_PASSWORD_POLICY_REF, prismContext, GLOBAL_PASSWORD_POLICY_OID);
deltas = MiscUtil.createCollection(sysConfigPasswordPolicyRefDelta);
modelService.executeChanges(deltas, null, task, result);
InternalsConfig.avoidLoggingChange = false;

//add user + assign role + assign org with the password policy specified
PrismObject<UserType> objectToAdd = PrismTestUtil.parseObject(USER_MIKE_FILE);
Expand All @@ -651,15 +663,15 @@ public void test200createUserAssignOrgPwdPolicy() throws Exception{

@Test
public void test201unassignRole() throws Exception{
final String TEST_NAME = "test200createUserAssignOrgPwdPolicy";
final String TEST_NAME = "test201unassignRole";
TestUtil.displayTestTile(this, TEST_NAME);
unassignRole(USER_MIKE_OID, ROLE_BASIC_OID);
//TODO: assertions
}

@Test
public void test202assignRoleOrgPwdPolicy() throws Exception{
final String TEST_NAME = "test200createUserAssignOrgPwdPolicy";
final String TEST_NAME = "test202assignRoleOrgPwdPolicy";
TestUtil.displayTestTile(this, TEST_NAME);

//this will throw exception, if incorrect pwd policy is selected...but some assertion will be nice :)
Expand All @@ -668,7 +680,31 @@ public void test202assignRoleOrgPwdPolicy() throws Exception{
//TODO: assertion
}


@Test
public void test300AddProjectJollyRoger() throws Exception {
final String TEST_NAME = "test300AddProjectJollyRoger";
TestUtil.displayTestTile(this, TEST_NAME);
Task task = taskManager.createTaskInstance(TestTrafo.class.getName() + "." + TEST_NAME);
OperationResult result = task.getResult();

// WHEN
TestUtil.displayWhen(TEST_NAME);
addObject(ORG_PROJECT_JOLLY_ROGER_FILE, task, result);

// THEN
TestUtil.displayThen(TEST_NAME);
result.computeStatus();
TestUtil.assertSuccess(result);

// TODO
PrismObject<OrgType> org = getObject(OrgType.class, ORG_PROJECT_JOLLY_ROGER_OID);
display("Org", org);
assertLinks(org, 2);

SearchResultEntry ouEntry = openDJController.fetchAndAssertEntry("ou=Jolly Roger,dc=example,dc=com", "organizationalUnit");
SearchResultEntry groupEntry = openDJController.fetchAndAssertEntry("cn=admins,ou=Jolly Roger,dc=example,dc=com", "groupOfUniqueNames");
//TODO: assertions
}


private void assertLocGov(PrismObject<UserType> user, String expLoc, String expOrg) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException {
Expand Down
32 changes: 16 additions & 16 deletions testing/story/src/test/resources/logback-test.xml
Expand Up @@ -29,35 +29,35 @@
<logger name="com.evolveum.midpoint.model.intest" level="TRACE" />
<logger name="com.evolveum.midpoint.model" level="DEBUG" />
<logger name="com.evolveum.midpoint.notifications" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.sync.LiveSyncTaskHandler" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.sync.ReconciliationTaskHandler" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.sync.SynchronizeAccountResultHandler" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.sync.LiveSyncTaskHandler" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.sync.ReconciliationTaskHandler" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.sync.SynchronizeAccountResultHandler" level="DEBUG" />
<logger name="com.evolveum.midpoint.provisioning.impl.ChangeNotificationDispatcherImpl" level="DEBUG" />
<logger name="com.evolveum.midpoint.test" level="TRACE" />
<logger name="PROFILING" level="OFF" />

<!-- "TRACE" is just too much info, "DEBUG" should be enough for the following talkative components ...
if any of the following is set to "TRACE" then it was changed by mistake and should be changed back -->
<logger name="com.evolveum.midpoint.model.lens.projector" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.lens.projector.Projector" level="TRACE" />
<logger name="com.evolveum.midpoint.model.lens" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.lens.AssignmentEvaluator" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.lens.Clockwork" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.lens.ChangeExecutor" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.lens.ShadowConstraintsChecker" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.lens.LensUtil" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.expr" level="TRACE" />
<logger name="com.evolveum.midpoint.model.util" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.sync" level="TRACE" />
<logger name="com.evolveum.midpoint.model.sync.CorrelationConfirmationEvaluator" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.projector" level="TRACE" />
<logger name="com.evolveum.midpoint.model.impl.lens.projector.Projector" level="TRACE" />
<logger name="com.evolveum.midpoint.model.impl.lens" level="TRACE" />
<logger name="com.evolveum.midpoint.model.impl.lens.AssignmentEvaluator" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.Clockwork" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.ChangeExecutor" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.ShadowConstraintsChecker" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.LensUtil" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.expr" level="TRACE" />
<logger name="com.evolveum.midpoint.model.impl.util" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.sync" level="TRACE" />
<logger name="com.evolveum.midpoint.model.impl.sync.CorrelationConfirmationEvaluator" level="DEBUG" />
<logger name="com.evolveum.midpoint.provisioning" level="DEBUG" />
<logger name="com.evolveum.midpoint.expression" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.common.expression" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.common.expression.Expression" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.common.mapping" level="DEBUG" />
<logger name="com.evolveum.midpoint.common.monitor" level="DEBUG" />
<logger name="com.evolveum.midpoint.notifications" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.controller.SystemConfigurationHandler" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.controller.SystemConfigurationHandler" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.common.expression.evaluator.AbstractSearchExpressionEvaluator" level="TRACE" />

<logger name="com.evolveum.midpoint.repo" level="INFO" />
Expand Down

0 comments on commit 1a93713

Please sign in to comment.