Search in sources :

Example 1 with Connector

use of org.identityconnectors.framework.spi.Connector in project midpoint by Evolveum.

the class ConnectorInstanceConnIdImpl method fetchChanges.

@Override
public UcfFetchChangesResult fetchChanges(ResourceObjectDefinition objectDefinition, UcfSyncToken initialTokenValue, AttributesToReturn attrsToReturn, Integer maxChanges, UcfExecutionContext ctx, @NotNull UcfLiveSyncChangeListener changeListener, OperationResult parentResult) throws CommunicationException, GenericFrameworkException, SchemaException {
    OperationResult result = parentResult.subresult(OP_FETCH_CHANGES).addArbitraryObjectAsContext("objectClass", objectDefinition).addArbitraryObjectAsParam("initialToken", initialTokenValue).build();
    try {
        SyncToken initialToken = TokenUtil.toConnId(initialTokenValue);
        LOGGER.trace("Initial token: {}", initialToken == null ? null : initialToken.getValue());
        ResourceObjectClassDefinition objectClassDefinition = objectDefinition != null ? objectDefinition.getObjectClassDefinition() : null;
        // get icf object class
        ObjectClass requestConnIdObjectClass;
        if (objectClassDefinition == null) {
            requestConnIdObjectClass = ObjectClass.ALL;
        } else {
            requestConnIdObjectClass = objectClassToConnId(objectClassDefinition);
        }
        OperationOptionsBuilder optionsBuilder = new OperationOptionsBuilder();
        if (objectDefinition != null) {
            convertToIcfAttrsToGet(objectDefinition, attrsToReturn, optionsBuilder);
        }
        OperationOptions options = optionsBuilder.build();
        AtomicInteger deltasProcessed = new AtomicInteger(0);
        Thread callerThread = Thread.currentThread();
        SyncDeltaConverter changeConverter = new SyncDeltaConverter(this, objectDefinition);
        AtomicBoolean allChangesFetched = new AtomicBoolean(true);
        UcfFetchChangesResult fetchChangesResult;
        OperationResult connIdResult = result.subresult(ConnectorFacade.class.getName() + ".sync").addContext("connector", connIdConnectorFacade.getClass()).addArbitraryObjectAsParam("objectClass", requestConnIdObjectClass).addArbitraryObjectAsParam("initialToken", initialToken).build();
        try {
            InternalMonitor.recordConnectorOperation("sync");
            ConnIdOperation operation = recordIcfOperationStart(ctx, ProvisioningOperation.ICF_SYNC, objectDefinition);
            /*
                 * We assume that the only way how changes are _not_ fetched is that we explicitly tell ConnId to stop
                 * fetching them by returning 'false' from the handler.handle() method. (Or an exception occurs in the sync()
                 * method.)
                 *
                 * In other words, we assume that if we tell ConnId to continue feeding changes to us, we are sure that on
                 * successful exit from sync() method all changes were processed.
                 */
            SyncResultsHandler syncHandler = syncDelta -> {
                Thread handlingThread = Thread.currentThread();
                if (!handlingThread.equals(callerThread)) {
                    LOGGER.warn("Live Sync changes are being processed in a thread {} that is different from the invoking one ({}). " + "This can cause issues e.g. with operational statistics reporting.", handlingThread, callerThread);
                }
                recordIcfOperationSuspend(ctx, operation);
                LOGGER.trace("Received sync delta: {}", syncDelta);
                OperationResult handleResult;
                // But - just for sure - let us create subresults in a safe way.
                synchronized (connIdResult) {
                    handleResult = connIdResult.subresult(OP_FETCH_CHANGES + ".handle").addArbitraryObjectAsParam("uid", syncDelta.getUid()).setMinor().build();
                }
                UcfLiveSyncChange change = null;
                try {
                    // Here we again assume we are called in a single thread, and that changes received here are in
                    // the correct order - i.e. in the order in which they are to be processed.
                    int sequentialNumber = deltasProcessed.incrementAndGet();
                    change = changeConverter.createChange(sequentialNumber, syncDelta, handleResult);
                    // The following should not throw any exceptions
                    boolean canContinue = changeListener.onChange(change, handleResult);
                    boolean doContinue = canContinue && canRun(ctx) && (maxChanges == null || maxChanges == 0 || sequentialNumber < maxChanges);
                    if (!doContinue) {
                        allChangesFetched.set(false);
                    }
                    return doContinue;
                } catch (RuntimeException e) {
                    handleResult.recordFatalError(e);
                    // any exception here is not expected
                    LoggingUtils.logUnexpectedException(LOGGER, "Got unexpected exception while handling live sync " + "change, stopping the processing. Sync delta: {}, UCF change: {}", e, syncDelta, change);
                    return false;
                } finally {
                    // Asynchronously processed changes (if used) have their own, separate, operation results
                    // that are tied to the lightweight asynchronous task handlers in ChangeProcessingCoordinator.
                    // 
                    // So we can safely compute/cleanup/summarize results here.
                    handleResult.computeStatusIfUnknown();
                    handleResult.cleanupResult();
                    connIdResult.summarize(true);
                    recordIcfOperationResume(ctx, operation);
                }
            };
            LOGGER.trace("Invoking ConnId sync operation: {}", operation);
            SyncToken finalToken;
            try {
                finalToken = connIdConnectorFacade.sync(requestConnIdObjectClass, initialToken, syncHandler, options);
                // Note that finalToken value is not quite reliable. The SyncApiOp documentation is not clear on its semantics;
                // it is only from SyncTokenResultsHandler (SPI) documentation and SyncImpl class that we know this value is
                // non-null when all changes were fetched. And some of the connectors return null even then.
                LOGGER.trace("connector sync method returned: {}", finalToken);
                connIdResult.computeStatus();
                connIdResult.cleanupResult();
                connIdResult.addReturn(OperationResult.RETURN_COUNT, deltasProcessed.get());
                recordIcfOperationEnd(ctx, operation, null);
            } catch (Throwable ex) {
                recordIcfOperationEnd(ctx, operation, ex);
                Throwable midpointEx = processConnIdException(ex, this, connIdResult);
                connIdResult.computeStatusIfUnknown();
                connIdResult.cleanupResult();
                result.computeStatus();
                // Do some kind of acrobatics to do proper throwing of checked exception
                if (midpointEx instanceof CommunicationException) {
                    throw (CommunicationException) midpointEx;
                } else if (midpointEx instanceof GenericFrameworkException) {
                    throw (GenericFrameworkException) midpointEx;
                } else if (midpointEx instanceof SchemaException) {
                    throw (SchemaException) midpointEx;
                } else if (midpointEx instanceof RuntimeException) {
                    throw (RuntimeException) midpointEx;
                } else if (midpointEx instanceof Error) {
                    throw (Error) midpointEx;
                } else {
                    throw new SystemException("Got unexpected exception: " + ex.getClass().getName() + ": " + ex.getMessage(), ex);
                }
            }
            if (!canRun(ctx)) {
                result.recordStatus(OperationResultStatus.SUCCESS, "Interrupted by task suspension");
            }
            if (allChangesFetched.get()) {
                // We might consider finalToken value here. I.e. it it's non null, we could declare all changes to be fetched.
                // But as mentioned above, this is not supported explicitly in SyncApiOp. So let's be a bit conservative.
                LOGGER.trace("All changes were fetched; with finalToken = {}", finalToken);
                fetchChangesResult = new UcfFetchChangesResult(true, TokenUtil.toUcf(finalToken));
            } else {
                fetchChangesResult = new UcfFetchChangesResult(false, null);
            }
        } catch (Throwable t) {
            connIdResult.recordFatalError(t);
            throw t;
        } finally {
            connIdResult.computeStatusIfUnknown();
        }
        result.recordSuccess();
        result.addReturn(OperationResult.RETURN_COUNT, deltasProcessed.get());
        return fetchChangesResult;
    } catch (Throwable t) {
        result.recordFatalError(t);
        throw t;
    } finally {
        result.computeStatusIfUnknown();
    }
}
Also used : SetUtils.emptyIfNull(org.apache.commons.collections4.SetUtils.emptyIfNull) ActivationUtil(com.evolveum.midpoint.schema.util.ActivationUtil) org.identityconnectors.framework.common.objects(org.identityconnectors.framework.common.objects) Filter(org.identityconnectors.framework.common.objects.filter.Filter) FilterInterpreter(com.evolveum.midpoint.provisioning.ucf.impl.connid.query.FilterInterpreter) com.evolveum.midpoint.util.exception(com.evolveum.midpoint.util.exception) APIConfigurationImpl(org.identityconnectors.framework.impl.api.APIConfigurationImpl) OperationResultStatus(com.evolveum.midpoint.schema.result.OperationResultStatus) BooleanUtils(org.apache.commons.lang.BooleanUtils) GuardedString(org.identityconnectors.common.security.GuardedString) ConnectorTestOperation(com.evolveum.midpoint.schema.constants.ConnectorTestOperation) AsynchronousOperationReturnValue(com.evolveum.midpoint.schema.result.AsynchronousOperationReturnValue) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConnIdUtil.processConnIdException(com.evolveum.midpoint.provisioning.ucf.impl.connid.ConnIdUtil.processConnIdException) com.evolveum.midpoint.prism(com.evolveum.midpoint.prism) XmlTypeConverter(com.evolveum.midpoint.prism.xml.XmlTypeConverter) Holder(com.evolveum.midpoint.util.Holder) ConnectorInfo(org.identityconnectors.framework.api.ConnectorInfo) Statistics(org.identityconnectors.framework.impl.api.local.ObjectPool.Statistics) ObjectPool(org.identityconnectors.framework.impl.api.local.ObjectPool) com.evolveum.midpoint.xml.ns._public.resource.capabilities_3(com.evolveum.midpoint.xml.ns._public.resource.capabilities_3) APIConfiguration(org.identityconnectors.framework.api.APIConfiguration) Nullable(org.jetbrains.annotations.Nullable) ConnIdOperation.getIdentifier(com.evolveum.midpoint.schema.reporting.ConnIdOperation.getIdentifier) Contract(org.jetbrains.annotations.Contract) DebugUtil.lazy(com.evolveum.midpoint.util.DebugUtil.lazy) ConnIdOperation(com.evolveum.midpoint.schema.reporting.ConnIdOperation) ConnectorOperationalContext(org.identityconnectors.framework.impl.api.local.operations.ConnectorOperationalContext) PropertyDelta(com.evolveum.midpoint.prism.delta.PropertyDelta) SearchResultMetadata(com.evolveum.midpoint.schema.SearchResultMetadata) QName(javax.xml.namespace.QName) ProvisioningOperation(com.evolveum.midpoint.schema.statistics.ProvisioningOperation) NotNull(org.jetbrains.annotations.NotNull) Validate(org.apache.commons.lang.Validate) LocalConnectorInfoImpl(org.identityconnectors.framework.impl.api.local.LocalConnectorInfoImpl) ProtectedStringType(com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType) UcfExecutionContext(com.evolveum.midpoint.provisioning.ucf.api.UcfExecutionContext) java.util(java.util) com.evolveum.midpoint.xml.ns._public.common.common_3(com.evolveum.midpoint.xml.ns._public.common.common_3) SchemaConstants(com.evolveum.midpoint.schema.constants.SchemaConstants) OperationResult(com.evolveum.midpoint.schema.result.OperationResult) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Connector(org.identityconnectors.framework.spi.Connector) Trace(com.evolveum.midpoint.util.logging.Trace) ObjectPoolConfiguration(org.identityconnectors.common.pooling.ObjectPoolConfiguration) LocalizationService(com.evolveum.midpoint.common.LocalizationService) PrettyPrinter(com.evolveum.midpoint.util.PrettyPrinter) ObjectFilter(com.evolveum.midpoint.prism.query.ObjectFilter) AlreadyExistsException(org.identityconnectors.framework.common.exceptions.AlreadyExistsException) PoolableConnector(org.identityconnectors.framework.spi.PoolableConnector) CapabilityUtil(com.evolveum.midpoint.schema.CapabilityUtil) ConnectorFacade(org.identityconnectors.framework.api.ConnectorFacade) ConnectorOperationalStatus(com.evolveum.midpoint.schema.statistics.ConnectorOperationalStatus) Collections.emptySet(java.util.Collections.emptySet) InternalMonitor(com.evolveum.midpoint.schema.internals.InternalMonitor) ConnectorFacadeFactory(org.identityconnectors.framework.api.ConnectorFacadeFactory) ItemPath(com.evolveum.midpoint.prism.path.ItemPath) LoggingUtils(com.evolveum.midpoint.util.logging.LoggingUtils) ItemName(com.evolveum.midpoint.prism.path.ItemName) com.evolveum.midpoint.provisioning.ucf.api(com.evolveum.midpoint.provisioning.ucf.api) com.evolveum.midpoint.schema.processor(com.evolveum.midpoint.schema.processor) AsynchronousOperationResult(com.evolveum.midpoint.schema.result.AsynchronousOperationResult) Protector(com.evolveum.midpoint.prism.crypto.Protector) ShadowUtil(com.evolveum.midpoint.schema.util.ShadowUtil) ObjectQuery(com.evolveum.midpoint.prism.query.ObjectQuery) OrderDirectionType(com.evolveum.prism.xml.ns._public.query_3.OrderDirectionType) TraceManager(com.evolveum.midpoint.util.logging.TraceManager) PrismSchema(com.evolveum.midpoint.prism.schema.PrismSchema) OperationResult(com.evolveum.midpoint.schema.result.OperationResult) AsynchronousOperationResult(com.evolveum.midpoint.schema.result.AsynchronousOperationResult) ConnIdOperation(com.evolveum.midpoint.schema.reporting.ConnIdOperation) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger)

Aggregations

LocalizationService (com.evolveum.midpoint.common.LocalizationService)1 com.evolveum.midpoint.prism (com.evolveum.midpoint.prism)1 Protector (com.evolveum.midpoint.prism.crypto.Protector)1 PropertyDelta (com.evolveum.midpoint.prism.delta.PropertyDelta)1 ItemName (com.evolveum.midpoint.prism.path.ItemName)1 ItemPath (com.evolveum.midpoint.prism.path.ItemPath)1 ObjectFilter (com.evolveum.midpoint.prism.query.ObjectFilter)1 ObjectQuery (com.evolveum.midpoint.prism.query.ObjectQuery)1 PrismSchema (com.evolveum.midpoint.prism.schema.PrismSchema)1 XmlTypeConverter (com.evolveum.midpoint.prism.xml.XmlTypeConverter)1 com.evolveum.midpoint.provisioning.ucf.api (com.evolveum.midpoint.provisioning.ucf.api)1 UcfExecutionContext (com.evolveum.midpoint.provisioning.ucf.api.UcfExecutionContext)1 ConnIdUtil.processConnIdException (com.evolveum.midpoint.provisioning.ucf.impl.connid.ConnIdUtil.processConnIdException)1 FilterInterpreter (com.evolveum.midpoint.provisioning.ucf.impl.connid.query.FilterInterpreter)1 CapabilityUtil (com.evolveum.midpoint.schema.CapabilityUtil)1 SearchResultMetadata (com.evolveum.midpoint.schema.SearchResultMetadata)1 ConnectorTestOperation (com.evolveum.midpoint.schema.constants.ConnectorTestOperation)1 SchemaConstants (com.evolveum.midpoint.schema.constants.SchemaConstants)1 InternalMonitor (com.evolveum.midpoint.schema.internals.InternalMonitor)1 com.evolveum.midpoint.schema.processor (com.evolveum.midpoint.schema.processor)1