public PropagationByResource update()

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;
    }