Skip to content

Commit

Permalink
Support for synchronization of ANY object class in provisioning (MID-…
Browse files Browse the repository at this point in the history
…2384)
  • Loading branch information
semancik committed May 29, 2015
1 parent 0475958 commit 822b70f
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 54 deletions.
Expand Up @@ -968,7 +968,16 @@ public void sync(ObjectClass objectClass, SyncToken token, SyncResultsHandler ha
}
}

SyncDeltaBuilder builder = new SyncDeltaBuilder();
SyncDeltaBuilder deltaBuilder = new SyncDeltaBuilder();
if (deltaObjectClass == DummyAccount.class) {
deltaBuilder.setObjectClass(ObjectClass.ACCOUNT);
} else if (deltaObjectClass == DummyGroup.class) {
deltaBuilder.setObjectClass(ObjectClass.GROUP);
} else if (deltaObjectClass == DummyPrivilege.class) {
deltaBuilder.setObjectClass(new ObjectClass(OBJECTCLASS_PRIVILEGE_NAME));
} else {
throw new IllegalArgumentException("Unknown delta objectClass "+deltaObjectClass);
}

SyncDeltaType deltaType;
if (delta.getType() == DummyDeltaType.ADD || delta.getType() == DummyDeltaType.MODIFY) {
Expand All @@ -987,14 +996,14 @@ public void sync(ObjectClass objectClass, SyncToken token, SyncResultsHandler ha
throw new IllegalStateException("We have delta for account '"+delta.getObjectId()+"' but such account does not exist");
}
ConnectorObject cobject = convertToConnectorObject(account, attributesToGet);
builder.setObject(cobject);
deltaBuilder.setObject(cobject);
} else if (deltaObjectClass == DummyGroup.class) {
DummyGroup group = resource.getGroupById(delta.getObjectId());
if (group == null) {
throw new IllegalStateException("We have delta for group '"+delta.getObjectId()+"' but such group does not exist");
}
ConnectorObject cobject = convertToConnectorObject(group, attributesToGet);
builder.setObject(cobject);
deltaBuilder.setObject(cobject);
} else {
throw new IllegalArgumentException("Unknown delta objectClass "+deltaObjectClass);
}
Expand All @@ -1003,9 +1012,9 @@ public void sync(ObjectClass objectClass, SyncToken token, SyncResultsHandler ha
} else {
throw new IllegalStateException("Unknown delta type "+delta.getType());
}
builder.setDeltaType(deltaType);
deltaBuilder.setDeltaType(deltaType);

builder.setToken(new SyncToken(delta.getSyncToken()));
deltaBuilder.setToken(new SyncToken(delta.getSyncToken()));

Uid uid;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
Expand All @@ -1015,9 +1024,9 @@ public void sync(ObjectClass objectClass, SyncToken token, SyncResultsHandler ha
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
builder.setUid(uid);
deltaBuilder.setUid(uid);

SyncDelta syncDelta = builder.build();
SyncDelta syncDelta = deltaBuilder.build();
log.info("sync::handle {0}",syncDelta);
handler.handle(syncDelta);
}
Expand Down Expand Up @@ -1172,6 +1181,7 @@ private ConnectorObject convertToConnectorObject(DummyAccount account, Collectio
}

ConnectorObjectBuilder builder = createConnectorObjectBuilderCommon(account, objectClass, attributesToGet, true);
builder.setObjectClass(ObjectClass.ACCOUNT);

// Password is not returned by default (hardcoded ICF specification)
if (account.getPassword() != null && configuration.getReadablePassword() &&
Expand All @@ -1190,12 +1200,14 @@ private ConnectorObject convertToConnectorObject(DummyAccount account, Collectio
private ConnectorObject convertToConnectorObject(DummyGroup group, Collection<String> attributesToGet) {
ConnectorObjectBuilder builder = createConnectorObjectBuilderCommon(group, resource.getGroupObjectClass(),
attributesToGet, true);
builder.setObjectClass(ObjectClass.GROUP);
return builder.build();
}

private ConnectorObject convertToConnectorObject(DummyPrivilege priv, Collection<String> attributesToGet) {
ConnectorObjectBuilder builder = createConnectorObjectBuilderCommon(priv, resource.getPrivilegeObjectClass(),
attributesToGet, false);
builder.setObjectClass(new ObjectClass(OBJECTCLASS_PRIVILEGE_NAME));
return builder.build();
}

Expand Down
Expand Up @@ -1462,30 +1462,54 @@ private boolean isAttributeDelta(ItemDelta itemDelta) {
}

public List<Change<ShadowType>> fetchChanges(ConnectorInstance connector, ResourceType resource,
RefinedObjectClassDefinition objectClass, PrismProperty<?> lastToken,
RefinedObjectClassDefinition objectClassDef, PrismProperty<?> lastToken,
OperationResult parentResult) throws SchemaException,
CommunicationException, ConfigurationException, SecurityViolationException, GenericFrameworkException, ObjectNotFoundException {
Validate.notNull(resource, "Resource must not be null.");
Validate.notNull(parentResult, "Operation result must not be null.");

LOGGER.trace("START fetch changes");
LOGGER.trace("START fetch changes, objectClass: {}", objectClassDef);

RefinedResourceSchema refinedSchema = null;
if (objectClassDef == null) {
refinedSchema = RefinedResourceSchema.getRefinedSchema(resource);
}

AttributesToReturn attrsToReturn = ProvisioningUtil.createAttributesToReturn(objectClass, resource);
AttributesToReturn attrsToReturn = null;
if (objectClassDef != null) {
attrsToReturn = ProvisioningUtil.createAttributesToReturn(objectClassDef, resource);
}

// get changes from the connector
List<Change<ShadowType>> changes = connector.fetchChanges(objectClass, lastToken, attrsToReturn, parentResult);
List<Change<ShadowType>> changes = connector.fetchChanges(objectClassDef, lastToken, attrsToReturn, parentResult);

Iterator<Change<ShadowType>> iterator = changes.iterator();
while (iterator.hasNext()) {
Change<ShadowType> change = iterator.next();
if (change.getCurrentShadow() == null) {

RefinedObjectClassDefinition shadowObjectClassDef = objectClassDef;
AttributesToReturn shadowAttrsToReturn = attrsToReturn;
PrismObject<ShadowType> currentShadow = change.getCurrentShadow();
if (objectClassDef == null) {
shadowObjectClassDef = refinedSchema.getRefinedDefinition(change.getObjectClassDefinition().getTypeName());
if (shadowObjectClassDef == null) {
String message = "Unkown object class "+change.getObjectClassDefinition().getTypeName()+" found in synchronization delta";
parentResult.recordFatalError(message);
throw new SchemaException(message);
}
change.setObjectClassDefinition(shadowObjectClassDef);

shadowAttrsToReturn = ProvisioningUtil.createAttributesToReturn(shadowObjectClassDef, resource);
}

if (currentShadow == null) {
// There is no current shadow in a change. Add it by fetching it explicitly.
if (change.getObjectDelta() == null || !change.getObjectDelta().isDelete()) {
// but not if it is a delete event
try {

PrismObject<ShadowType> currentShadow = fetchResourceObject(connector, resource, objectClass,
change.getIdentifiers(), attrsToReturn, true, parentResult); // todo consider whether it is always necessary to fetch the entitlements
currentShadow = fetchResourceObject(connector, resource, shadowObjectClassDef,
change.getIdentifiers(), shadowAttrsToReturn, true, parentResult); // todo consider whether it is always necessary to fetch the entitlements
change.setCurrentShadow(currentShadow);

} catch (ObjectNotFoundException ex) {
Expand All @@ -1499,9 +1523,18 @@ public List<Change<ShadowType>> fetchChanges(ConnectorInstance connector, Resour
}
}
} else {
PrismObject<ShadowType> currentShadow = postProcessResourceObjectRead(connector, resource, change.getCurrentShadow(),
objectClass, true, parentResult);
change.setCurrentShadow(currentShadow);
if (objectClassDef == null) {
if (!MiscUtil.equals(shadowAttrsToReturn, attrsToReturn)) {
// re-fetch the shadow if necessary (if attributesToGet does not match)
ResourceObjectIdentification identification = new ResourceObjectIdentification(shadowObjectClassDef, change.getIdentifiers());
currentShadow = connector.fetchObject(ShadowType.class, identification, shadowAttrsToReturn, parentResult);
}

}

PrismObject<ShadowType> processedCurrentShadow = postProcessResourceObjectRead(connector, resource, currentShadow,
shadowObjectClassDef, true, parentResult);
change.setCurrentShadow(processedCurrentShadow);
}
}

Expand Down
Expand Up @@ -1037,9 +1037,6 @@ public List<Change<ShadowType>> fetchChanges(ResourceType resourceType,
InternalMonitor.recordShadowOtherOperation();

RefinedObjectClassDefinition refinedObjectClassDefinition = determineObjectClassDefinition(objectClass, resourceType);
if (refinedObjectClassDefinition == null) {
throw new SchemaException("Unknown object class "+objectClass+" in "+resourceType);
}
ConnectorInstance connector = getConnectorInstance(resourceType, parentResult);

List<Change<ShadowType>> changes = null;
Expand All @@ -1049,12 +1046,14 @@ public List<Change<ShadowType>> fetchChanges(ResourceType resourceType,

LOGGER.trace("Found {} change(s). Start processing it (them).", changes.size());

for (Iterator<Change<ShadowType>> i = changes.iterator(); i.hasNext();) {
// search objects in repository
Change<ShadowType> change = i.next();
for (Change<ShadowType> change: changes) {

processChange(resourceType, refinedObjectClassDefinition, objectClass, parentResult, change, connector);

QName shadowObjectClass = objectClass;
if (shadowObjectClass == null) {
shadowObjectClass = change.getObjectClassDefinition().getTypeName();
}

processChange(resourceType, refinedObjectClassDefinition, shadowObjectClass, parentResult, change, connector);
}

} catch (SchemaException ex) {
Expand Down
Expand Up @@ -1046,7 +1046,7 @@ public <T extends ShadowType> PrismObject<T> fetchObject(Class<T> type,
throw ex;
} catch (ObjectNotFoundException ex) {
result.recordFatalError("Object not found");
throw new ObjectNotFoundException("Object identified by " + identifiers + " was not found by "
throw new ObjectNotFoundException("Object identified by " + identifiers + ", objectClass " + objectClassDefinition.getTypeName() + " was not found by "
+ connectorType);
} catch (SchemaException ex) {
result.recordFatalError(ex);
Expand All @@ -1058,7 +1058,7 @@ public <T extends ShadowType> PrismObject<T> fetchObject(Class<T> type,

if (co == null) {
result.recordFatalError("Object not found");
throw new ObjectNotFoundException("Object identified by " + identifiers + " was not found by "
throw new ObjectNotFoundException("Object identified by " + identifiers + ", objectClass " + objectClassDefinition.getTypeName() + " was not found by "
+ connectorType);
}

Expand Down Expand Up @@ -1846,10 +1846,18 @@ public <T extends ShadowType> List<Change<T>> fetchChanges(ObjectClassComplexTy

final List<SyncDelta> syncDeltas = new ArrayList<SyncDelta>();
// get icf object class
ObjectClass icfObjectClass = icfNameMapper.objectClassToIcf(objectClass, getSchemaNamespace(), connectorType, legacySchema);
ObjectClass icfObjectClass;
if (objectClass == null) {
icfObjectClass = ObjectClass.ALL;
} else {
icfObjectClass = icfNameMapper.objectClassToIcf(objectClass, getSchemaNamespace(), connectorType, legacySchema);
}

OperationOptionsBuilder optionsBuilder = new OperationOptionsBuilder();
String[] attributesToGet = convertToIcfAttrsToGet(objectClass, attrsToReturn);
String[] attributesToGet = null;
if (objectClass != null) {
attributesToGet = convertToIcfAttrsToGet(objectClass, attrsToReturn);
}
if (attributesToGet != null) {
optionsBuilder.setAttributesToGet(attributesToGet);
}
Expand All @@ -1861,7 +1869,6 @@ public <T extends ShadowType> List<Change<T>> fetchChanges(ObjectClassComplexTy
public boolean handle(SyncDelta delta) {
LOGGER.trace("Detected sync delta: {}", delta);
return syncDeltas.add(delta);

}
};

Expand Down Expand Up @@ -2281,15 +2288,6 @@ private ResourceAttributeDefinition getUidDefinition(Collection<? extends Resour
return null;
}










private void convertFromActivation(Set<Attribute> updateAttributes,
Collection<PropertyDelta<?>> activationDeltas) throws SchemaException {

Expand Down Expand Up @@ -2352,39 +2350,50 @@ private void convertFromPassword(Set<Attribute> attributes, PropertyDelta<Protec

}

private <T extends ShadowType> List<Change<T>> getChangesFromSyncDeltas(ObjectClass objClass, Collection<SyncDelta> icfDeltas, PrismSchema schema,
private <T extends ShadowType> List<Change<T>> getChangesFromSyncDeltas(ObjectClass icfObjClass, Collection<SyncDelta> icfDeltas, PrismSchema schema,
OperationResult parentResult)
throws SchemaException, GenericFrameworkException {
List<Change<T>> changeList = new ArrayList<Change<T>>();

QName objectClass = icfNameMapper.objectClassToQname(icfObjClass.getObjectClassValue(), getSchemaNamespace(), legacySchema);
ObjectClassComplexTypeDefinition objClassDefinition = null;
if (objectClass != null) {
objClassDefinition = (ObjectClassComplexTypeDefinition) schema.findComplexTypeDefinition(objectClass);
}

Validate.notNull(icfDeltas, "Sync result must not be null.");
for (SyncDelta icfDelta : icfDeltas) {

if (icfDelta.getObject() != null){
objClass = icfDelta.getObject().getObjectClass();
ObjectClass deltaIcfObjClass = icfObjClass;
QName deltaObjectClass = objectClass;
ObjectClassComplexTypeDefinition deltaObjClassDefinition = objClassDefinition;
if (objectClass == null) {
deltaIcfObjClass = icfDelta.getObjectClass();
deltaObjectClass = icfNameMapper.objectClassToQname(deltaIcfObjClass.getObjectClassValue(), getSchemaNamespace(), legacySchema);
deltaObjClassDefinition = (ObjectClassComplexTypeDefinition) schema.findComplexTypeDefinition(deltaObjectClass);
}
QName objectClass = icfNameMapper.objectClassToQname(objClass.getObjectClassValue(), getSchemaNamespace(), legacySchema);
ObjectClassComplexTypeDefinition objClassDefinition = (ObjectClassComplexTypeDefinition) schema
.findComplexTypeDefinition(objectClass);

if (deltaObjClassDefinition == null) {
throw new SchemaException("Got delta with object class "+deltaObjectClass+" ("+deltaIcfObjClass+") that has no definition in resource schema");
}
SyncDeltaType icfDeltaType = icfDelta.getDeltaType();
if (SyncDeltaType.DELETE.equals(icfDeltaType)) {
LOGGER.trace("START creating delta of type DELETE");
ObjectDelta<ShadowType> objectDelta = new ObjectDelta<ShadowType>(
ShadowType.class, ChangeType.DELETE, prismContext);
ResourceAttribute<String> uidAttribute = IcfUtil.createUidAttribute(
icfDelta.getUid(),
IcfUtil.getUidDefinition(objClassDefinition
IcfUtil.getUidDefinition(deltaObjClassDefinition
.toResourceAttributeContainerDefinition(ShadowType.F_ATTRIBUTES)));
Collection<ResourceAttribute<?>> identifiers = new ArrayList<ResourceAttribute<?>>(1);
identifiers.add(uidAttribute);
Change change = new Change(identifiers, objectDelta, getToken(icfDelta.getToken()));
change.setObjectClassDefinition(objClassDefinition);
change.setObjectClassDefinition(deltaObjClassDefinition);
changeList.add(change);
LOGGER.trace("END creating delta of type DELETE");

} else if (SyncDeltaType.CREATE.equals(icfDeltaType)) {
PrismObjectDefinition<ShadowType> objectDefinition = toShadowDefinition(objClassDefinition);
PrismObjectDefinition<ShadowType> objectDefinition = toShadowDefinition(deltaObjClassDefinition);
LOGGER.trace("Object definition: {}", objectDefinition);

LOGGER.trace("START creating delta of type CREATE");
Expand All @@ -2402,13 +2411,13 @@ private <T extends ShadowType> List<Change<T>> getChangesFromSyncDeltas(ObjectCl
objectDelta.setObjectToAdd(currentShadow);

Change change = new Change(identifiers, objectDelta, getToken(icfDelta.getToken()));
change.setObjectClassDefinition(objClassDefinition);
change.setObjectClassDefinition(deltaObjClassDefinition);
changeList.add(change);
LOGGER.trace("END creating delta of type CREATE");

} else if (SyncDeltaType.CREATE_OR_UPDATE.equals(icfDeltaType) ||
SyncDeltaType.UPDATE.equals(icfDeltaType)) {
PrismObjectDefinition<ShadowType> objectDefinition = toShadowDefinition(objClassDefinition);
PrismObjectDefinition<ShadowType> objectDefinition = toShadowDefinition(deltaObjClassDefinition);
LOGGER.trace("Object definition: {}", objectDefinition);

LOGGER.trace("START creating delta of type {}", icfDeltaType);
Expand All @@ -2422,7 +2431,7 @@ private <T extends ShadowType> List<Change<T>> getChangesFromSyncDeltas(ObjectCl
Collection<ResourceAttribute<?>> identifiers = ShadowUtil.getIdentifiers(currentShadow);

Change change = new Change(identifiers, currentShadow, getToken(icfDelta.getToken()));
change.setObjectClassDefinition(objClassDefinition);
change.setObjectClassDefinition(deltaObjClassDefinition);
changeList.add(change);
LOGGER.trace("END creating delta of type {}", icfDeltaType);

Expand Down
Expand Up @@ -132,6 +132,9 @@ private String toCamelCase(String upcase, boolean lowCase) {
* TODO: mind the special characters in the ICF objectclass names.
*/
public QName objectClassToQname(String icfObjectClassString, String schemaNamespace, boolean legacySchema) {
if (ObjectClass.ALL_NAME.equals(icfObjectClassString)) {
return null;
}
if (legacySchema) {
if (ObjectClass.ACCOUNT_NAME.equals(icfObjectClassString)) {
return new QName(schemaNamespace, ConnectorFactoryIcfImpl.ACCOUNT_OBJECT_CLASS_LOCAL_NAME,
Expand Down

0 comments on commit 822b70f

Please sign in to comment.