Skip to content

Commit

Permalink
fixing inbound - outbound processing for dependency..
Browse files Browse the repository at this point in the history
  • Loading branch information
katkav committed Oct 2, 2014
1 parent 80501d9 commit d4896e7
Show file tree
Hide file tree
Showing 15 changed files with 190 additions and 22 deletions.
Expand Up @@ -44,6 +44,7 @@ public class DummyConfiguration extends AbstractConfiguration {
private boolean requireExplicitEnable = false;
private boolean caseIgnoreId = false;
private boolean caseIgnoreValues = false;
private boolean generateDefaultValues = false;
private boolean tolerateDuplicateValues = true;
private String uselessString;
private GuardedString uselessGuardedString;
Expand Down Expand Up @@ -160,6 +161,19 @@ public boolean getCaseIgnoreId() {
public void setCaseIgnoreId(boolean caseIgnoreId) {
this.caseIgnoreId = caseIgnoreId;
}

/**
* If set to true then the "home dir" will be generated
*/
@ConfigurationProperty(displayMessageKey = "UI_GENERATE_DEFAULT_VALUES",
helpMessageKey = "UI_GENERATE_DEFAULT_VALUES")
public boolean isGenerateDefaultValues() {
return generateDefaultValues;
}

public void setGenerateDefaultValues(boolean generateDefaultValues) {
this.generateDefaultValues = generateDefaultValues;
}

/**
* If set to true then the attribute values will be considered case-insensitive
Expand Down
Expand Up @@ -144,6 +144,7 @@ public void init(Configuration configuration) {
resource.setCaseIgnoreValues(this.configuration.getCaseIgnoreValues());
resource.setEnforceUniqueName(this.configuration.isEnforceUniqueName());
resource.setTolerateDuplicateValues(this.configuration.getTolerateDuplicateValues());
resource.setGenerateDefaultValues(this.configuration.isGenerateDefaultValues());

resource.setUselessString(this.configuration.getUselessString());
GuardedString uselessGuardedString = this.configuration.getUselessGuardedString();
Expand Down Expand Up @@ -227,6 +228,8 @@ public Uid create(final ObjectClass objectClass, final Set<Attribute> createAttr
throw new ConnectionFailedException(e.getMessage(), e);
} catch (FileNotFoundException e) {
throw new ConnectorIOException(e.getMessage(), e);
} catch (SchemaViolationException e) {
throw new ConnectorException(e);
}

String id;
Expand Down Expand Up @@ -1065,7 +1068,7 @@ private ConnectorObjectBuilder createConnectorObjectBuilderCommon(DummyObject du
(attributesToGet == null || attributesToGet.contains(OperationalAttributes.DISABLE_DATE_NAME))) {
builder.addAttribute(OperationalAttributes.DISABLE_DATE_NAME, convertToLong(dummyObject.getValidTo()));
}
}
}

return builder;
}
Expand Down
Expand Up @@ -38,6 +38,7 @@ public class DummyAccount extends DummyObject {
public static final String ATTR_DESCRIPTION_NAME = "description";
public static final String ATTR_INTERESTS_NAME = "interests";
public static final String ATTR_PRIVILEGES_NAME = "privileges";
public static final String ATTR_INTERNAL_ID = "internalId";

private String password = null;
private Boolean lockout = null;
Expand Down
Expand Up @@ -41,6 +41,7 @@
public abstract class DummyObject implements DebugDumpable {

private String id;
// private int internalId = -1;
private String name;
private Map<String,Set<Object>> attributes = new HashMap<String, Set<Object>>();
private boolean enabled = true;
Expand All @@ -60,7 +61,7 @@ public String getId() {
public void setId(String id) {
this.id = id;
}

public DummyObject(String name) {
this.name = name;
}
Expand Down
Expand Up @@ -77,6 +77,7 @@ public class DummyResource implements DebugDumpable {
private List<DummyDelta> deltas;
private int latestSyncToken;
private boolean tolerateDuplicateValues = false;
private boolean generateDefaultValues = false;
private boolean enforceUniqueName = true;
private boolean enforceSchema = true;
private boolean caseIgnoreId = false;
Expand All @@ -88,6 +89,7 @@ public class DummyResource implements DebugDumpable {
private BreakMode modifyBreakMode = BreakMode.NONE;
private BreakMode deleteBreakMode = BreakMode.NONE;


// Following two properties are just copied from the connector
// configuration and can be checked later. They are otherwise
// completely useless.
Expand Down Expand Up @@ -149,6 +151,14 @@ public void setTolerateDuplicateValues(boolean tolerateDuplicateValues) {
this.tolerateDuplicateValues = tolerateDuplicateValues;
}

public boolean isGenerateDefaultValues() {
return generateDefaultValues;
}

public void setGenerateDefaultValues(boolean generateDefaultValues) {
this.generateDefaultValues = generateDefaultValues;
}

public boolean isEnforceUniqueName() {
return enforceUniqueName;
}
Expand Down Expand Up @@ -418,7 +428,7 @@ public Collection<DummyPrivilege> listPrivileges() throws ConnectException, File
}
}

private synchronized <T extends DummyObject> String addObject(Map<String,T> map, T newObject) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException {
private synchronized <T extends DummyObject> String addObject(Map<String,T> map, T newObject) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException, SchemaViolationException {
if (addBreakMode == BreakMode.NONE) {
// just go on
} else if (addBreakMode == BreakMode.NETWORK) {
Expand Down Expand Up @@ -446,6 +456,13 @@ private synchronized <T extends DummyObject> String addObject(Map<String,T> map,
throw new IllegalStateException("The hell is frozen over. The impossible has happened. ID "+newId+" already exists ("+ type.getSimpleName()+" with identifier "+normalName+")");
}

//this is "resource-generated" attribute (used to simulate resource which generate by default attributes which we need to sync)
if (generateDefaultValues){
int internalId = allObjects.size();
newObject.addAttributeValue(DummyAccount.ATTR_INTERNAL_ID, internalId++);
}


String mapKey;
if (enforceUniqueName) {
mapKey = normalName;
Expand All @@ -470,6 +487,7 @@ private synchronized <T extends DummyObject> String addObject(Map<String,T> map,
return newObject.getName();
}


private synchronized <T extends DummyObject> void deleteObjectByName(Class<T> type, Map<String,T> map, String name) throws ObjectDoesNotExistException, ConnectException, FileNotFoundException {
if (deleteBreakMode == BreakMode.NONE) {
// go on
Expand Down Expand Up @@ -615,7 +633,7 @@ private <T extends DummyObject> void renameObject(Class<T> type, Map<String,T> m
existingObject.setName(newName);
}

public String addAccount(DummyAccount newAccount) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException {
public String addAccount(DummyAccount newAccount) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException, SchemaViolationException {
return addObject(accounts, newAccount);
}

Expand All @@ -627,7 +645,7 @@ public void renameAccount(String id, String oldUsername, String newUsername) thr
renameObject(DummyAccount.class, accounts, id, oldUsername, newUsername);
}

public String addGroup(DummyGroup newGroup) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException {
public String addGroup(DummyGroup newGroup) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException, SchemaViolationException {
return addObject(groups, newGroup);
}

Expand All @@ -639,7 +657,7 @@ public void renameGroup(String id, String oldName, String newName) throws Object
renameObject(DummyGroup.class, groups, id, oldName, newName);
}

public String addPrivilege(DummyPrivilege newGroup) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException {
public String addPrivilege(DummyPrivilege newGroup) throws ObjectAlreadyExistsException, ConnectException, FileNotFoundException, SchemaViolationException {
return addObject(privileges, newGroup);
}

Expand Down Expand Up @@ -692,6 +710,7 @@ public void runScript(String language, String scriptCode, Map<String, Object> pa
public void populateWithDefaultSchema() {
accountObjectClass.clear();
accountObjectClass.addAttributeDefinition(DummyAccount.ATTR_FULLNAME_NAME, String.class, true, false);
accountObjectClass.addAttributeDefinition(DummyAccount.ATTR_INTERNAL_ID, String.class, false, false);
accountObjectClass.addAttributeDefinition(DummyAccount.ATTR_DESCRIPTION_NAME, String.class, false, false);
accountObjectClass.addAttributeDefinition(DummyAccount.ATTR_INTERESTS_NAME, String.class, false, true);
accountObjectClass.addAttributeDefinition(DummyAccount.ATTR_PRIVILEGES_NAME, String.class, false, true);
Expand Down
Expand Up @@ -595,7 +595,7 @@ public static <F extends ObjectType> void loadFullAccount(LensContext<F> context
// already loaded
return;
}
if (accCtx.isAdd()) {
if (accCtx.isAdd() && accCtx.getOid() == null) {
// nothing to load yet
return;
}
Expand Down
Expand Up @@ -215,6 +215,7 @@ private <F extends FocusType> void processAssignmentsProjectionsWithFocus(LensCo
LOGGER.trace("Current assignments {}", SchemaDebugUtil.prettyPrint(assignmentsCurrent));
LOGGER.trace("Changed assignments {}", SchemaDebugUtil.prettyPrint(changedAssignments));

// ObjectType source = determineSource(focusContext);
ObjectType source = null;
if (focusContext.getObjectCurrent() != null) {
source = focusContext.getObjectCurrent().asObjectable();
Expand Down Expand Up @@ -635,6 +636,20 @@ private <F extends FocusType> void processAssignmentsProjectionsWithFocus(LensCo

}

private <F extends ObjectType> ObjectType determineSource(LensFocusContext<F> focusContext)
throws SchemaException {
ObjectDelta delta = focusContext.getWaveDelta(focusContext.getLensContext().getExecutionWave());
if (delta != null && !delta.isEmpty()) {
return focusContext.getObjectNew().asObjectable();
}

if (focusContext.getObjectCurrent() != null) {
return focusContext.getObjectCurrent().asObjectable();
}

return focusContext.getObjectNew().asObjectable();
}

private <F extends FocusType> void collectToZero(DeltaSetTriple<EvaluatedAssignment<F>> evaluatedAssignmentTriple,
EvaluatedAssignment<F> evaluatedAssignment, boolean forceRecon) {
evaluatedAssignment.setForceRecon(forceRecon);
Expand Down
Expand Up @@ -30,6 +30,7 @@
import com.evolveum.midpoint.common.Clock;
import com.evolveum.midpoint.common.refinery.ResourceShadowDiscriminator;
import com.evolveum.midpoint.model.api.PolicyViolationException;
import com.evolveum.midpoint.model.api.context.ModelState;
import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision;
import com.evolveum.midpoint.model.impl.lens.LensContext;
import com.evolveum.midpoint.model.impl.lens.LensFocusContext;
Expand Down Expand Up @@ -406,15 +407,20 @@ public <F extends ObjectType> boolean checkDependencies(LensContext<F> context,
|| strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) {
if (wasProvisioned(dependencyAccountContext, context.getExecutionWave())) {
// everything OK
if (ResourceTypeUtil.isForceLoadDependentShadow(dependency) && !dependencyAccountContext.isFullShadow()){
try {
LensUtil.loadFullAccount(context, dependencyAccountContext, provisioningService, result);
} catch (ObjectNotFoundException | CommunicationException | SchemaException
| ConfigurationException | SecurityViolationException e) {
// this is not fatal error. we can continue without full account..the incosinstencies will be treaten later, by reconciliation
LOGGER.warn("Could not load dependent shadow, continue with the shadow loaded before.");
}
}
// if (ResourceTypeUtil.isForceLoadDependentShadow(dependency) && !dependencyAccountContext.isDelete()){
// LOGGER.info("FORCE TO LOAD FULL ACCOUNT " + dependencyAccountContext);
// try {
// LensUtil.loadFullAccount(context, dependencyAccountContext, provisioningService, result);
// dependencyAccountContext.setDoReconciliation(true);
// if (dependencyAccountContext.getExecutedDeltas() != null && !dependencyAccountContext.getExecutedDeltas().isEmpty()){
// context.resetProjectionWave();
// }
// } catch (ObjectNotFoundException | CommunicationException | SchemaException
// | ConfigurationException | SecurityViolationException e) {
// // this is not fatal error. we can continue without full account..the incosinstencies will be treaten later, by reconciliation
// LOGGER.warn("Could not load dependent shadow, continue with the shadow loaded before.");
// }
// }
} 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.
Expand All @@ -434,6 +440,45 @@ public <F extends ObjectType> boolean checkDependencies(LensContext<F> context,
return true;
}

public <F extends ObjectType> void preprocessDependencies(LensContext<F> context){

//in the first wave we do not have enougth information to preprocess connetxts
if (context.getExecutionWave() == 0){
return;
}

for (LensProjectionContext projContext : context.getProjectionContexts()){

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){
// We have the context of the object that we depend on. We need to check if it was provisioned.
if (strictness == ResourceObjectTypeDependencyStrictnessType.STRICT
|| strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) {
if (wasExecuted(dependencyAccountContext)) {
// everything OK
if (ResourceTypeUtil.isForceLoadDependentShadow(dependency) && !dependencyAccountContext.isDelete()){
LOGGER.info("FORCE TO LOAD FULL ACCOUNT " + dependencyAccountContext);
dependencyAccountContext.setDoReconciliation(true);
projContext.setDoReconciliation(true);
// if (dependencyAccountContext.getExecutedDeltas() != null && !dependencyAccountContext.getExecutedDeltas().isEmpty()){
// if (context.getProjectionWave() < context.getExecutionWave()){
// context.resetProjectionWave();
// }
// }
}
}
}
}
}
}

}

/**
* Finally checks for all the dependencies. Some dependencies cannot be checked during wave computations as
* we might not have all activation decisions yet.
Expand Down Expand Up @@ -484,14 +529,18 @@ private <F extends ObjectType> boolean wasProvisioned(LensProjectionContext acco
|| accountContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) {
return false;
}


PrismObject<ShadowType> objectCurrent = accountContext.getObjectCurrent();
if (objectCurrent != null && objectCurrent.asObjectable().getFailedOperationType() != null) {
// There is unfinished operation in the shadow. We cannot continue.
return false;
}
}

if (accountContext.isExists()) {
return true;
}

if (accountContext.isAdd()) {
List<LensObjectDeltaOperation<ShadowType>> executedDeltas = accountContext.getExecutedDeltas();
if (executedDeltas == null || executedDeltas.isEmpty()) {
Expand All @@ -505,8 +554,24 @@ private <F extends ObjectType> boolean wasProvisioned(LensProjectionContext acco
}
return true;
}

return false;
}

private boolean wasExecuted(LensProjectionContext accountContext){
if (accountContext.isAdd()) {

if (accountContext.getOid() == null){
return false;
}

List<LensObjectDeltaOperation<ShadowType>> executedDeltas = accountContext.getExecutedDeltas();
if (executedDeltas == null || executedDeltas.isEmpty()) {
return false;
}
}
return true;
}

class DependencyAndSource {
ResourceObjectTypeDependencyType dependency;
Expand Down
Expand Up @@ -152,12 +152,15 @@ public <F extends ObjectType> void project(LensContext<F> context, String activi
LOGGER.trace("WAVE: Starting the waves.");
context.setProjectionWave(0);
while (context.getProjectionWave() < maxWaves) {

context.checkAbortRequested();

LOGGER.trace("WAVE {} (maxWaves={}, executionWave={})", new Object[]{
context.getProjectionWave(), maxWaves, context.getExecutionWave()});

//just make sure everythink is loaded and set as needed
dependencyProcessor.preprocessDependencies(context);

// Process the focus-related aspects of the context. That means inbound, focus activation,
// object template and assignments.
focusProcessor.processFocus(context, activityDescription, now, task, result);
Expand Down
Expand Up @@ -2189,6 +2189,15 @@ protected void assertDummyAccountAttribute(String dummyInstanceName, String user
}
}
}

protected void assertDummyAccountAttributeGenerated(String dummyInstanceName, String username) {
DummyAccount account = getDummyAccount(dummyInstanceName, username);
assertNotNull("No dummy account for username "+username, account);
Integer generated = account.getAttributeValue(DummyAccount.ATTR_INTERNAL_ID, Integer.class);
if (generated == null) {
AssertJUnit.fail("No value in generated attribute dir of " + dummyInstanceName + " dummy account " + username);
}
}

protected DummyGroup getDummyGroup(String dummyInstanceName, String name) {
DummyResource dummyResource = DummyResource.getInstance(dummyInstanceName);
Expand Down
Expand Up @@ -239,7 +239,7 @@ public void assertDummyResourceSchemaSanityExtended(ResourceSchema resourceSchem
assertDummyResourceSchemaSanity(resourceSchema, resourceType);

ObjectClassComplexTypeDefinition accountDef = resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT);
assertEquals("Unexpected number of defnitions", 16, accountDef.getDefinitions().size());
assertEquals("Unexpected number of defnitions", 17, accountDef.getDefinitions().size());
ResourceAttributeDefinition treasureDef = accountDef.findAttributeDefinition(DUMMY_ACCOUNT_ATTRIBUTE_TREASURE_NAME);
assertFalse("Treasure IS returned by default and should not be", treasureDef.isReturnedByDefault());
}
Expand Down

0 comments on commit d4896e7

Please sign in to comment.