Search in sources :

Example 1 with GenericConnectorException

use of com.evolveum.midpoint.provisioning.api.GenericConnectorException in project midpoint by Evolveum.

the class ResourceObjectReferenceResolver method fetchResourceObject.

public PrismObject<ShadowType> fetchResourceObject(ProvisioningContext ctx, Collection<? extends ResourceAttribute<?>> identifiers, AttributesToReturn attributesToReturn, OperationResult parentResult) throws ObjectNotFoundException, CommunicationException, SchemaException, SecurityViolationException, ConfigurationException, ExpressionEvaluationException {
    ResourceType resource = ctx.getResource();
    ConnectorInstance connector = ctx.getConnector(ReadCapabilityType.class, parentResult);
    RefinedObjectClassDefinition objectClassDefinition = ctx.getObjectClassDefinition();
    try {
        if (!ResourceTypeUtil.isReadCapabilityEnabled(resource)) {
            throw new UnsupportedOperationException("Resource does not support 'read' operation");
        }
        ResourceObjectIdentification identification = ResourceObjectIdentification.create(objectClassDefinition, identifiers);
        identification = resolvePrimaryIdentifiers(ctx, identification, parentResult);
        identification.validatePrimaryIdenfiers();
        return connector.fetchObject(ShadowType.class, identification, attributesToReturn, ctx, parentResult);
    } catch (ObjectNotFoundException e) {
        parentResult.recordFatalError("Object not found. Identifiers: " + identifiers + ". Reason: " + e.getMessage(), e);
        throw new ObjectNotFoundException("Object not found. identifiers=" + identifiers + ", objectclass=" + PrettyPrinter.prettyPrint(objectClassDefinition.getTypeName()) + ": " + e.getMessage(), e);
    } catch (CommunicationException e) {
        parentResult.recordFatalError("Error communication with the connector " + connector + ": " + e.getMessage(), e);
        throw e;
    } catch (GenericFrameworkException e) {
        parentResult.recordFatalError("Generic error in the connector " + connector + ". Reason: " + e.getMessage(), e);
        throw new GenericConnectorException("Generic error in the connector " + connector + ". Reason: " + e.getMessage(), e);
    } catch (SchemaException ex) {
        parentResult.recordFatalError("Can't get resource object, schema error: " + ex.getMessage(), ex);
        throw ex;
    } catch (ExpressionEvaluationException ex) {
        parentResult.recordFatalError("Can't get resource object, expression error: " + ex.getMessage(), ex);
        throw ex;
    } catch (ConfigurationException e) {
        parentResult.recordFatalError(e);
        throw e;
    }
}
Also used : RefinedObjectClassDefinition(com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition) SchemaException(com.evolveum.midpoint.util.exception.SchemaException) ConnectorInstance(com.evolveum.midpoint.provisioning.ucf.api.ConnectorInstance) ExpressionEvaluationException(com.evolveum.midpoint.util.exception.ExpressionEvaluationException) CommunicationException(com.evolveum.midpoint.util.exception.CommunicationException) GenericFrameworkException(com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException) ResourceObjectIdentification(com.evolveum.midpoint.schema.processor.ResourceObjectIdentification) GenericConnectorException(com.evolveum.midpoint.provisioning.api.GenericConnectorException) ConfigurationException(com.evolveum.midpoint.util.exception.ConfigurationException) ObjectNotFoundException(com.evolveum.midpoint.util.exception.ObjectNotFoundException) ResourceType(com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType)

Example 2 with GenericConnectorException

use of com.evolveum.midpoint.provisioning.api.GenericConnectorException in project midpoint by Evolveum.

the class EntitlementConverter method postProcessEntitlementEntitlementToSubject.

private <S extends ShadowType, T> void postProcessEntitlementEntitlementToSubject(ProvisioningContext subjectCtx, final PrismObject<S> resourceObject, RefinedAssociationDefinition assocDefType, final ProvisioningContext entitlementCtx, ResourceAttributeContainer attributesContainer, final PrismContainer<ShadowAssociationType> associationContainer, OperationResult parentResult) throws SchemaException, CommunicationException, ObjectNotFoundException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
    ResourceType resourceType = subjectCtx.getResource();
    final QName associationName = assocDefType.getName();
    final RefinedObjectClassDefinition entitlementDef = entitlementCtx.getObjectClassDefinition();
    if (associationName == null) {
        throw new SchemaException("No name in entitlement association " + assocDefType + " in " + resourceType);
    }
    QName associationAuxiliaryObjectClass = assocDefType.getAuxiliaryObjectClass();
    if (associationAuxiliaryObjectClass != null && associationAuxiliaryObjectClass.getNamespaceURI() != null && !associationAuxiliaryObjectClass.getNamespaceURI().equals(ResourceTypeUtil.getResourceNamespace(resourceType))) {
        LOGGER.warn("Auxiliary object class {} in association {} does not have namespace that matches {}", associationAuxiliaryObjectClass, assocDefType.getName(), resourceType);
    }
    if (associationAuxiliaryObjectClass != null && !subjectCtx.getObjectClassDefinition().hasAuxiliaryObjectClass(associationAuxiliaryObjectClass)) {
        LOGGER.trace("Ignoring association {} because subject does not have auxiliary object class {}, it has {}", associationName, associationAuxiliaryObjectClass, subjectCtx.getObjectClassDefinition().getAuxiliaryObjectClassDefinitions());
        return;
    }
    QName assocAttrName = assocDefType.getResourceObjectAssociationType().getAssociationAttribute();
    if (assocAttrName == null) {
        throw new SchemaException("No association attribute defined in entitlement association '" + associationName + "' in " + resourceType);
    }
    RefinedAttributeDefinition assocAttrDef = entitlementDef.findAttributeDefinition(assocAttrName);
    if (assocAttrDef == null) {
        throw new SchemaException("Association attribute '" + assocAttrName + "'defined in entitlement association '" + associationName + "' was not found in schema for " + resourceType);
    }
    QName valueAttrName = assocDefType.getResourceObjectAssociationType().getValueAttribute();
    if (valueAttrName == null) {
        throw new SchemaException("No value attribute defined in entitlement association '" + associationName + "' in " + resourceType);
    }
    ResourceAttribute<T> valueAttr = attributesContainer.findAttribute(valueAttrName);
    if (valueAttr == null || valueAttr.isEmpty()) {
        LOGGER.trace("Ignoring association {} because subject does not have any value in attribute {}", associationName, valueAttrName);
        return;
    }
    if (valueAttr.size() > 1) {
        throw new SchemaException("Value attribute " + valueAttrName + " has no more than one value; attribute defined in entitlement association '" + associationName + "' in " + resourceType);
    }
    ObjectQuery query = createQuery(assocDefType, assocAttrDef, valueAttr);
    AttributesToReturn attributesToReturn = ProvisioningUtil.createAttributesToReturn(entitlementCtx);
    SearchHierarchyConstraints searchHierarchyConstraints = null;
    ResourceObjectReferenceType baseContextRef = entitlementDef.getBaseContext();
    if (baseContextRef != null) {
        // TODO: this should be done once per search. Not in every run of postProcessEntitlementEntitlementToSubject
        // this has to go outside of this method
        PrismObject<ShadowType> baseContextShadow = resourceObjectReferenceResolver.resolve(subjectCtx, baseContextRef, null, "base context specification in " + entitlementDef, parentResult);
        RefinedObjectClassDefinition baseContextObjectClassDefinition = subjectCtx.getRefinedSchema().determineCompositeObjectClassDefinition(baseContextShadow);
        ResourceObjectIdentification baseContextIdentification = ShadowUtil.getResourceObjectIdentification(baseContextShadow, baseContextObjectClassDefinition);
        searchHierarchyConstraints = new SearchHierarchyConstraints(baseContextIdentification, null);
    }
    ResultHandler<ShadowType> handler = new ResultHandler<ShadowType>() {

        @Override
        public boolean handle(PrismObject<ShadowType> entitlementShadow) {
            PrismContainerValue<ShadowAssociationType> associationCVal = associationContainer.createNewValue();
            associationCVal.asContainerable().setName(associationName);
            Collection<ResourceAttribute<?>> entitlementIdentifiers = ShadowUtil.getAllIdentifiers(entitlementShadow);
            try {
                ResourceAttributeContainer identifiersContainer = new ResourceAttributeContainer(ShadowAssociationType.F_IDENTIFIERS, entitlementDef.toResourceAttributeContainerDefinition(), prismContext);
                associationCVal.add(identifiersContainer);
                identifiersContainer.getValue().addAll(ResourceAttribute.cloneCollection(entitlementIdentifiers));
                // Remember the full shadow in user data. This is used later as an optimization to create the shadow in repo 
                identifiersContainer.setUserData(ResourceObjectConverter.FULL_SHADOW_KEY, entitlementShadow);
                if (LOGGER.isTraceEnabled()) {
                    LOGGER.trace("Processed entitlement-to-subject association for account {} and entitlement {}", ShadowUtil.getHumanReadableName(resourceObject), ShadowUtil.getHumanReadableName(entitlementShadow));
                }
            } catch (SchemaException e) {
                throw new TunnelException(e);
            }
            return true;
        }
    };
    ConnectorInstance connector = subjectCtx.getConnector(ReadCapabilityType.class, parentResult);
    try {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Processed entitlement-to-subject association for account {}: query {}", ShadowUtil.getHumanReadableName(resourceObject), query);
        }
        try {
            connector.search(entitlementDef, query, handler, attributesToReturn, null, searchHierarchyConstraints, subjectCtx, parentResult);
        } catch (GenericFrameworkException e) {
            throw new GenericConnectorException("Generic error in the connector " + connector + ". Reason: " + e.getMessage(), e);
        }
    } catch (TunnelException e) {
        throw (SchemaException) e.getCause();
    }
}
Also used : AttributesToReturn(com.evolveum.midpoint.provisioning.ucf.api.AttributesToReturn) ResourceAttributeContainer(com.evolveum.midpoint.schema.processor.ResourceAttributeContainer) ResultHandler(com.evolveum.midpoint.provisioning.ucf.api.ResultHandler) PrismObject(com.evolveum.midpoint.prism.PrismObject) TunnelException(com.evolveum.midpoint.util.exception.TunnelException) SearchHierarchyConstraints(com.evolveum.midpoint.schema.processor.SearchHierarchyConstraints) ResourceObjectIdentification(com.evolveum.midpoint.schema.processor.ResourceObjectIdentification) GenericConnectorException(com.evolveum.midpoint.provisioning.api.GenericConnectorException) ResourceObjectReferenceType(com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectReferenceType) ResourceAttribute(com.evolveum.midpoint.schema.processor.ResourceAttribute) ShadowAssociationType(com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAssociationType) SchemaException(com.evolveum.midpoint.util.exception.SchemaException) GenericFrameworkException(com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException) QName(javax.xml.namespace.QName) ShadowType(com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType) ResourceType(com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType) ObjectQuery(com.evolveum.midpoint.prism.query.ObjectQuery) ConnectorInstance(com.evolveum.midpoint.provisioning.ucf.api.ConnectorInstance)

Example 3 with GenericConnectorException

use of com.evolveum.midpoint.provisioning.api.GenericConnectorException in project midpoint by Evolveum.

the class ProvisioningServiceImpl method synchronize.

@SuppressWarnings("rawtypes")
@Override
public int synchronize(ResourceShadowDiscriminator shadowCoordinates, Task task, OperationResult parentResult) throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
    Validate.notNull(shadowCoordinates, "Coordinates oid must not be null.");
    String resourceOid = shadowCoordinates.getResourceOid();
    Validate.notNull(resourceOid, "Resource oid must not be null.");
    Validate.notNull(task, "Task must not be null.");
    Validate.notNull(parentResult, "Operation result must not be null.");
    OperationResult result = parentResult.createSubresult(ProvisioningService.class.getName() + ".synchronize");
    result.addParam(OperationResult.PARAM_OID, resourceOid);
    result.addParam(OperationResult.PARAM_TASK, task.toString());
    int processedChanges = 0;
    try {
        // Resolve resource
        PrismObject<ResourceType> resource = getObject(ResourceType.class, resourceOid, null, task, result);
        ResourceType resourceType = resource.asObjectable();
        LOGGER.trace("**PROVISIONING: Start synchronization of resource {} ", resourceType);
        // getting token form task
        PrismProperty tokenProperty = getTokenProperty(shadowCoordinates, task, result);
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("**PROVISIONING: Got token property: {} from the task extension.", SchemaDebugUtil.prettyPrint(tokenProperty));
        }
        processedChanges = getShadowCache(Mode.STANDARD).synchronize(shadowCoordinates, tokenProperty, task, result);
        LOGGER.debug("Synchronization of {} done, token {}, {} changes", resource, tokenProperty, processedChanges);
    } catch (ObjectNotFoundException e) {
        ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: object not found: " + e.getMessage(), e);
        throw e;
    } catch (CommunicationException e) {
        ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: communication problem: " + e.getMessage(), e);
        throw e;
    } catch (ObjectAlreadyExistsException e) {
        ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: object already exists problem: " + e.getMessage(), e);
        throw new SystemException(e);
    } catch (GenericFrameworkException e) {
        ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: generic connector framework error: " + e.getMessage(), e);
        throw new GenericConnectorException(e.getMessage(), e);
    } catch (SchemaException e) {
        ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: schema problem: " + e.getMessage(), e);
        throw e;
    } catch (SecurityViolationException e) {
        ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: security violation: " + e.getMessage(), e);
        throw e;
    } catch (ConfigurationException e) {
        ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: configuration problem: " + e.getMessage(), e);
        throw e;
    } catch (RuntimeException e) {
        ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: unexpected problem: " + e.getMessage(), e);
        throw e;
    } catch (ExpressionEvaluationException e) {
        ProvisioningUtil.recordFatalError(LOGGER, result, "Synchronization error: expression error: " + e.getMessage(), e);
        throw e;
    }
    result.recordSuccess();
    result.cleanupResult();
    return processedChanges;
}
Also used : SchemaException(com.evolveum.midpoint.util.exception.SchemaException) ExpressionEvaluationException(com.evolveum.midpoint.util.exception.ExpressionEvaluationException) CommunicationException(com.evolveum.midpoint.util.exception.CommunicationException) GenericFrameworkException(com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException) SecurityViolationException(com.evolveum.midpoint.util.exception.SecurityViolationException) OperationResult(com.evolveum.midpoint.schema.result.OperationResult) ResourceType(com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType) LabeledString(com.evolveum.midpoint.schema.LabeledString) PrismProperty(com.evolveum.midpoint.prism.PrismProperty) SystemException(com.evolveum.midpoint.util.exception.SystemException) GenericConnectorException(com.evolveum.midpoint.provisioning.api.GenericConnectorException) ConfigurationException(com.evolveum.midpoint.util.exception.ConfigurationException) ObjectNotFoundException(com.evolveum.midpoint.util.exception.ObjectNotFoundException) ObjectAlreadyExistsException(com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException)

Example 4 with GenericConnectorException

use of com.evolveum.midpoint.provisioning.api.GenericConnectorException in project midpoint by Evolveum.

the class ResourceObjectConverter method deleteResourceObject.

public AsynchronousOperationResult deleteResourceObject(ProvisioningContext ctx, PrismObject<ShadowType> shadow, OperationProvisioningScriptsType scripts, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
    OperationResult result = parentResult.createSubresult(OPERATION_DELETE_RESOURCE_OBJECT);
    LOGGER.trace("Deleting resource object {}", shadow);
    Collection<? extends ResourceAttribute<?>> identifiers = ShadowUtil.getAllIdentifiers(shadow);
    if (ProvisioningUtil.isProtectedShadow(ctx.getObjectClassDefinition(), shadow, matchingRuleRegistry)) {
        LOGGER.error("Attempt to delete protected resource object " + ctx.getObjectClassDefinition() + ": " + identifiers + "; ignoring the request");
        SecurityViolationException e = new SecurityViolationException("Cannot delete protected resource object " + ctx.getObjectClassDefinition() + ": " + identifiers);
        result.recordFatalError(e);
        throw e;
    }
    //check idetifier if it is not null
    if (identifiers.isEmpty() && shadow.asObjectable().getFailedOperationType() != null) {
        throw new GenericConnectorException("Unable to delete object from the resource. Probably it has not been created yet because of previous unavailability of the resource.");
    }
    // Execute entitlement modification on other objects (if needed)
    executeEntitlementChangesDelete(ctx, shadow, scripts, result);
    Collection<Operation> additionalOperations = new ArrayList<Operation>();
    addExecuteScriptOperation(additionalOperations, ProvisioningOperationTypeType.DELETE, scripts, ctx.getResource(), result);
    ConnectorInstance connector = ctx.getConnector(DeleteCapabilityType.class, result);
    try {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("PROVISIONING DELETE operation on {}\n DELETE object, object class {}, identified by:\n{}\n additional operations:\n{}", ctx.getResource(), shadow.asObjectable().getObjectClass(), SchemaDebugUtil.debugDump(identifiers), SchemaDebugUtil.debugDump(additionalOperations));
        }
        if (!ResourceTypeUtil.isDeleteCapabilityEnabled(ctx.getResource())) {
            UnsupportedOperationException e = new UnsupportedOperationException("Resource does not support 'delete' operation");
            result.recordFatalError(e);
            throw e;
        }
        connector.deleteObject(ctx.getObjectClassDefinition(), additionalOperations, identifiers, ctx, result);
        computeResultStatus(result);
        LOGGER.debug("PROVISIONING DELETE: {}", result.getStatus());
    } catch (ObjectNotFoundException ex) {
        result.recordFatalError("Can't delete object " + shadow + ". Reason: " + ex.getMessage(), ex);
        throw new ObjectNotFoundException("An error occured while deleting resource object " + shadow + "whith identifiers " + identifiers + ": " + ex.getMessage(), ex);
    } catch (CommunicationException ex) {
        result.recordFatalError("Error communicating with the connector " + connector + ": " + ex.getMessage(), ex);
        throw new CommunicationException("Error communicating with the connector " + connector + ": " + ex.getMessage(), ex);
    } catch (ConfigurationException ex) {
        result.recordFatalError("Configuration error in connector " + connector + ": " + ex.getMessage(), ex);
        throw new ConfigurationException("Configuration error in connector " + connector + ": " + ex.getMessage(), ex);
    } catch (ExpressionEvaluationException ex) {
        result.recordFatalError("Expression error while setting up the resource: " + ex.getMessage(), ex);
        throw new ExpressionEvaluationException("Expression error while setting up the resource: " + ex.getMessage(), ex);
    } catch (GenericFrameworkException ex) {
        result.recordFatalError("Generic error in connector: " + ex.getMessage(), ex);
        throw new GenericConnectorException("Generic error in connector: " + ex.getMessage(), ex);
    }
    LOGGER.trace("Deleted resource object {}", shadow);
    return AsynchronousOperationResult.wrap(result);
}
Also used : OperationResult(com.evolveum.midpoint.schema.result.OperationResult) AsynchronousOperationResult(com.evolveum.midpoint.schema.result.AsynchronousOperationResult) GenericConnectorException(com.evolveum.midpoint.provisioning.api.GenericConnectorException)

Example 5 with GenericConnectorException

use of com.evolveum.midpoint.provisioning.api.GenericConnectorException in project midpoint by Evolveum.

the class ResourceObjectConverter method modifyResourceObject.

public AsynchronousOperationReturnValue<Collection<PropertyDelta<PrismPropertyValue>>> modifyResourceObject(ProvisioningContext ctx, PrismObject<ShadowType> repoShadow, OperationProvisioningScriptsType scripts, Collection<? extends ItemDelta> itemDeltas, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ObjectAlreadyExistsException, ExpressionEvaluationException {
    OperationResult result = parentResult.createSubresult(OPERATION_MODIFY_RESOURCE_OBJECT);
    try {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Modifying resource object {}, deltas:\n", repoShadow, DebugUtil.debugDump(itemDeltas, 1));
        }
        RefinedObjectClassDefinition objectClassDefinition = ctx.getObjectClassDefinition();
        Collection<Operation> operations = new ArrayList<Operation>();
        Collection<? extends ResourceAttribute<?>> identifiers = ShadowUtil.getAllIdentifiers(repoShadow);
        Collection<? extends ResourceAttribute<?>> primaryIdentifiers = ShadowUtil.getPrimaryIdentifiers(repoShadow);
        if (ProvisioningUtil.isProtectedShadow(ctx.getObjectClassDefinition(), repoShadow, matchingRuleRegistry)) {
            if (hasChangesOnResource(itemDeltas)) {
                LOGGER.error("Attempt to modify protected resource object " + objectClassDefinition + ": " + identifiers);
                SecurityViolationException e = new SecurityViolationException("Cannot modify protected resource object " + objectClassDefinition + ": " + identifiers);
                result.recordFatalError(e);
                throw e;
            } else {
                // Return immediately. This structure of the code makes sure that we do not execute any
                // resource operation for protected account even if there is a bug in the code below.
                LOGGER.trace("No resource modifications for protected resource object {}: {}; skipping", objectClassDefinition, identifiers);
                result.recordNotApplicableIfUnknown();
                return AsynchronousOperationReturnValue.wrap(null, result);
            }
        }
        boolean hasVolatilityTriggerModification = false;
        boolean hasResourceModification = false;
        for (ItemDelta modification : itemDeltas) {
            ItemPath path = modification.getPath();
            QName firstPathName = ItemPath.getFirstName(path);
            if (QNameUtil.match(firstPathName, ShadowType.F_ATTRIBUTES)) {
                hasResourceModification = true;
                QName attrName = ItemPath.getFirstName(path.rest());
                RefinedAttributeDefinition<Object> attrDef = ctx.getObjectClassDefinition().findAttributeDefinition(attrName);
                if (attrDef.isVolatilityTrigger()) {
                    LOGGER.trace("Will pre-read and re-read object because volatility trigger attribute {} has changed", attrName);
                    hasVolatilityTriggerModification = true;
                    break;
                }
            } else if (QNameUtil.match(firstPathName, ShadowType.F_ACTIVATION) || QNameUtil.match(firstPathName, ShadowType.F_CREDENTIALS) || QNameUtil.match(firstPathName, ShadowType.F_ASSOCIATION) || QNameUtil.match(firstPathName, ShadowType.F_AUXILIARY_OBJECT_CLASS)) {
                hasResourceModification = true;
            }
        }
        if (!hasResourceModification) {
            // Quit early, so we avoid potential pre-read and other processing when there is no point of doing so.
            // Also the read may fail which may invoke consistency mechanism which will complicate the situation.
            LOGGER.trace("No resource modification found for {}, skipping", identifiers);
            result.recordNotApplicableIfUnknown();
            return AsynchronousOperationReturnValue.wrap(null, result);
        }
        /*
	         *  State of the shadow before execution of the deltas - e.g. with original attributes, as it may be recorded in such a way in
	         *  groups of which this account is a member of. (In case of object->subject associations.)
	         *
	         *  This is used when the resource does NOT provide referential integrity by itself. This is e.g. the case of OpenDJ with default
	         *  settings.
	         *
	         *  On the contrary, AD and OpenDJ with referential integrity plugin do provide automatic referential integrity, so this feature is
	         *  not needed.
	         *
	         *  We decide based on setting of explicitReferentialIntegrity in association definition.
	         */
        collectAttributeAndEntitlementChanges(ctx, itemDeltas, operations, repoShadow, result);
        PrismObject<ShadowType> preReadShadow = null;
        Collection<PropertyModificationOperation> sideEffectOperations = null;
        //check identifier if it is not null
        if (primaryIdentifiers.isEmpty() && repoShadow.asObjectable().getFailedOperationType() != null) {
            GenericConnectorException e = new GenericConnectorException("Unable to modify object in the resource. Probably it has not been created yet because of previous unavailability of the resource.");
            result.recordFatalError(e);
            throw e;
        }
        if (hasVolatilityTriggerModification || ResourceTypeUtil.isAvoidDuplicateValues(ctx.getResource()) || isRename(ctx, operations)) {
            // We need to filter out the deltas that add duplicate values or remove values that are not there
            LOGGER.trace("Pre-reading resource shadow");
            // yes, we need associations here
            preReadShadow = preReadShadow(ctx, identifiers, operations, true, result);
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Pre-read object:\n{}", preReadShadow.debugDump());
            }
        }
        if (!operations.isEmpty()) {
            // This must go after the skip check above. Otherwise the scripts would be executed even if there is no need to.
            addExecuteScriptOperation(operations, ProvisioningOperationTypeType.MODIFY, scripts, ctx.getResource(), result);
            // Execute primary ICF operation on this shadow
            sideEffectOperations = executeModify(ctx, preReadShadow, identifiers, operations, result);
        } else {
            // We have to check BEFORE we add script operations, otherwise the check would be pointless
            LOGGER.trace("No modifications for connector object specified. Skipping processing of subject executeModify.");
        }
        Collection<PropertyDelta<PrismPropertyValue>> sideEffectDeltas = convertToPropertyDelta(sideEffectOperations);
        /*
	         *  State of the shadow after execution of the deltas - e.g. with new DN (if it was part of the delta), because this one should be recorded
	         *  in groups of which this account is a member of. (In case of object->subject associations.)
	         */
        PrismObject<ShadowType> shadowAfter = preReadShadow == null ? repoShadow.clone() : preReadShadow.clone();
        for (ItemDelta itemDelta : itemDeltas) {
            itemDelta.applyTo(shadowAfter);
        }
        PrismObject<ShadowType> postReadShadow = null;
        if (hasVolatilityTriggerModification) {
            // There may be other changes that were not detected by the connector. Re-read the object and compare.
            LOGGER.trace("Post-reading resource shadow");
            postReadShadow = preReadShadow(ctx, identifiers, operations, true, result);
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Post-read object:\n{}", postReadShadow.debugDump());
            }
            ObjectDelta<ShadowType> resourceShadowDelta = preReadShadow.diff(postReadShadow);
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Determined side-effect changes by old-new diff:\n{}", resourceShadowDelta.debugDump());
            }
            for (ItemDelta modification : resourceShadowDelta.getModifications()) {
                if (modification.getParentPath().startsWithName(ShadowType.F_ATTRIBUTES) && !ItemDelta.hasEquivalent(itemDeltas, modification)) {
                    ItemDelta.merge(sideEffectDeltas, modification);
                }
            }
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Side-effect changes after merging with old-new diff:\n{}", DebugUtil.debugDump(sideEffectDeltas));
            }
        }
        Collection<? extends ItemDelta> allDeltas = new ArrayList<>();
        ((Collection) allDeltas).addAll(itemDeltas);
        ((Collection) allDeltas).addAll(sideEffectDeltas);
        // Execute entitlement modification on other objects (if needed)
        shadowAfter = executeEntitlementChangesModify(ctx, preReadShadow == null ? repoShadow : preReadShadow, postReadShadow == null ? shadowAfter : postReadShadow, scripts, allDeltas, result);
        if (!sideEffectDeltas.isEmpty()) {
            if (preReadShadow != null) {
                PrismUtil.setDeltaOldValue(preReadShadow, sideEffectDeltas);
            } else {
                PrismUtil.setDeltaOldValue(repoShadow, sideEffectDeltas);
            }
        }
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Modificaiton side-effect changes:\n{}", DebugUtil.debugDump(sideEffectDeltas));
        }
        LOGGER.trace("Modified resource object {}", repoShadow);
        computeResultStatus(result);
        return AsynchronousOperationReturnValue.wrap(sideEffectDeltas, result);
    } catch (Throwable e) {
        result.recordFatalError(e);
        throw e;
    }
}
Also used : QName(javax.xml.namespace.QName) OperationResult(com.evolveum.midpoint.schema.result.OperationResult) AsynchronousOperationResult(com.evolveum.midpoint.schema.result.AsynchronousOperationResult) ItemDelta(com.evolveum.midpoint.prism.delta.ItemDelta) GenericConnectorException(com.evolveum.midpoint.provisioning.api.GenericConnectorException) PropertyDelta(com.evolveum.midpoint.prism.delta.PropertyDelta) ItemPath(com.evolveum.midpoint.prism.path.ItemPath)

Aggregations

GenericConnectorException (com.evolveum.midpoint.provisioning.api.GenericConnectorException)11 GenericFrameworkException (com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException)5 OperationResult (com.evolveum.midpoint.schema.result.OperationResult)5 ObjectQuery (com.evolveum.midpoint.prism.query.ObjectQuery)4 ConnectorInstance (com.evolveum.midpoint.provisioning.ucf.api.ConnectorInstance)4 AsynchronousOperationResult (com.evolveum.midpoint.schema.result.AsynchronousOperationResult)4 QName (javax.xml.namespace.QName)4 ItemPath (com.evolveum.midpoint.prism.path.ItemPath)3 ResourceObjectIdentification (com.evolveum.midpoint.schema.processor.ResourceObjectIdentification)3 SchemaException (com.evolveum.midpoint.util.exception.SchemaException)3 ResourceType (com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType)3 PrismObject (com.evolveum.midpoint.prism.PrismObject)2 ItemDelta (com.evolveum.midpoint.prism.delta.ItemDelta)2 PropertyDelta (com.evolveum.midpoint.prism.delta.PropertyDelta)2 AttributesToReturn (com.evolveum.midpoint.provisioning.ucf.api.AttributesToReturn)2 ResultHandler (com.evolveum.midpoint.provisioning.ucf.api.ResultHandler)2 ResourceAttributeContainer (com.evolveum.midpoint.schema.processor.ResourceAttributeContainer)2 SearchHierarchyConstraints (com.evolveum.midpoint.schema.processor.SearchHierarchyConstraints)2 CommunicationException (com.evolveum.midpoint.util.exception.CommunicationException)2 ConfigurationException (com.evolveum.midpoint.util.exception.ConfigurationException)2