in core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java [293:464]
public PropagationByResource<String> update(final AnyObject toBeUpdated, final AnyObjectUR anyObjectUR) {
// Re-merge any pending change from workflow tasks
AnyObject anyObject = anyObjectDAO.save(toBeUpdated);
AnyObjectTO anyTO = AnyOperations.patch(getAnyObjectTO(anyObject, true), anyObjectUR);
PropagationByResource<String> propByRes = new PropagationByResource<>();
// Save projection on Resources (before update)
Map<String, ConnObject> beforeOnResources =
onResources(anyObject, anyObjectDAO.findAllResourceKeys(anyObject.getKey()), null, Set.of());
SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
AnyUtils anyUtils = anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT);
// realm
setRealm(anyObject, anyObjectUR);
// name
if (anyObjectUR.getName() != null && StringUtils.isNotBlank(anyObjectUR.getName().getValue())) {
anyObject.setName(anyObjectUR.getName().getValue());
}
// attributes and resources
fill(anyTO, anyObject, anyObjectUR, anyUtils, scce);
// relationships
Set<Pair<String, String>> relationships = new HashSet<>();
anyObjectUR.getRelationships().stream().
filter(patch -> patch.getRelationshipTO() != null).forEach(patch -> {
RelationshipType relationshipType = relationshipTypeDAO.findById(
patch.getRelationshipTO().getType()).orElse(null);
if (relationshipType == null) {
LOG.debug("Ignoring invalid relationship type {}", patch.getRelationshipTO().getType());
} else {
anyObject.getRelationship(relationshipType, patch.getRelationshipTO().getOtherEndKey()).
ifPresent(relationship -> {
anyObject.getRelationships().remove(relationship);
relationship.setLeftEnd(null);
});
if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
if (StringUtils.isBlank(patch.getRelationshipTO().getOtherEndType())
|| AnyTypeKind.USER.name().equals(patch.getRelationshipTO().getOtherEndType())
|| AnyTypeKind.GROUP.name().equals(patch.getRelationshipTO().getOtherEndType())) {
SyncopeClientException invalidAnyType =
SyncopeClientException.build(ClientExceptionType.InvalidAnyType);
invalidAnyType.getElements().add(AnyType.class.getSimpleName()
+ " not allowed for relationship: " + patch.getRelationshipTO().getOtherEndType());
scce.addException(invalidAnyType);
} else {
AnyObject otherEnd = anyObjectDAO.findById(patch.getRelationshipTO().getOtherEndKey()).
orElse(null);
if (otherEnd == null) {
LOG.debug("Ignoring invalid any object {}", patch.getRelationshipTO().getOtherEndKey());
} else if (patch.getRelationshipTO().getEnd() == RelationshipTO.End.RIGHT) {
SyncopeClientException noRight =
SyncopeClientException.build(ClientExceptionType.InvalidRelationship);
noRight.getElements().add(
"Relationships shall be created or updated only from their left end");
scce.addException(noRight);
} else if (relationships.contains(
Pair.of(otherEnd.getKey(), patch.getRelationshipTO().getType()))) {
SyncopeClientException assigned =
SyncopeClientException.build(ClientExceptionType.InvalidRelationship);
assigned.getElements().add("AnyObject was already in relationship "
+ patch.getRelationshipTO().getType() + " with "
+ otherEnd.getType().getKey() + " " + otherEnd.getName());
scce.addException(assigned);
} else {
relationships.add(Pair.of(otherEnd.getKey(), patch.getRelationshipTO().getType()));
ARelationship newRelationship = entityFactory.newEntity(ARelationship.class);
newRelationship.setType(relationshipType);
newRelationship.setRightEnd(otherEnd);
newRelationship.setLeftEnd(anyObject);
anyObject.add(newRelationship);
}
}
}
}
});
SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
// memberships
Set<String> groups = new HashSet<>();
anyObjectUR.getMemberships().stream().filter(patch -> patch.getGroup() != null).forEach(patch -> {
anyObject.getMembership(patch.getGroup()).ifPresent(membership -> {
anyObject.remove(membership);
membership.setLeftEnd(null);
anyObject.getPlainAttrs(membership).forEach(anyObject::remove);
anyObjectDAO.deleteMembership(membership);
if (patch.getOperation() == PatchOperation.DELETE) {
propByRes.addAll(
ResourceOperation.UPDATE,
groupDAO.findAllResourceKeys((membership.getRightEnd().getKey())));
}
});
if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
Group group = groupDAO.findById(patch.getGroup()).orElse(null);
if (group == null) {
LOG.debug("Ignoring invalid group {}", patch.getGroup());
} else if (groups.contains(group.getKey())) {
LOG.error("Multiple patches for group {} of {} were found", group, anyObject);
SyncopeClientException assigned =
SyncopeClientException.build(ClientExceptionType.InvalidMembership);
assigned.getElements().add("Multiple patches for group " + group.getName() + " were found");
scce.addException(assigned);
} else {
groups.add(group.getKey());
AMembership newMembership = entityFactory.newEntity(AMembership.class);
newMembership.setRightEnd(group);
newMembership.setLeftEnd(anyObject);
anyObject.add(newMembership);
patch.getPlainAttrs().forEach(attrTO -> getPlainSchema(attrTO.getSchema()).ifPresentOrElse(
schema -> anyObject.getPlainAttr(schema.getKey(), newMembership).ifPresentOrElse(
attr -> LOG.debug(
"Plain attribute found for {} and membership of {}, nothing to do",
schema, newMembership.getRightEnd()),
() -> {
LOG.debug("No plain attribute found for {} and membership of {}",
schema, newMembership.getRightEnd());
PlainAttr newAttr = new PlainAttr();
newAttr.setMembership(newMembership.getKey());
newAttr.setPlainSchema(schema);
anyObject.add(newAttr);
processAttrPatch(
anyTO,
anyObject,
new AttrPatch.Builder(attrTO).build(),
schema,
newAttr,
invalidValues);
}),
() -> LOG.debug("Invalid {}{}, ignoring...",
PlainSchema.class.getSimpleName(), attrTO.getSchema())));
if (!invalidValues.isEmpty()) {
scce.addException(invalidValues);
}
propByRes.addAll(ResourceOperation.UPDATE, groupDAO.findAllResourceKeys(group.getKey()));
}
}
});
// Throw composite exception if there is at least one element set in the composing exceptions
if (scce.hasExceptions()) {
throw scce;
}
// Re-merge any pending change from above
AnyObject saved = anyObjectDAO.save(anyObject);
// Build final information for next stage (propagation)
propByRes.merge(propByRes(
beforeOnResources,
onResources(saved, anyObjectDAO.findAllResourceKeys(anyObject.getKey()), null, Set.of())));
return propByRes;
}