use of org.identityconnectors.framework.impl.api.local.ObjectPool.Statistics 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();
}
}
use of org.identityconnectors.framework.impl.api.local.ObjectPool.Statistics in project midpoint by Evolveum.
the class ConnectorInstanceConnIdImpl method getOperationalStatus.
@Override
public ConnectorOperationalStatus getOperationalStatus() throws ObjectNotFoundException {
if (!(connectorInfo instanceof LocalConnectorInfoImpl)) {
LOGGER.trace("Cannot get operational status of a remote connector {}", connectorType);
return null;
}
if (apiConfig == null) {
LOGGER.trace("Cannot get operational status of a connector {}: connector not yet configured", connectorType);
throw new IllegalStateException("Connector " + connectorType + " not yet configured");
}
ConnectorOperationalStatus status = new ConnectorOperationalStatus();
ConnectorOperationalContext connectorOperationalContext = new ConnectorOperationalContext((LocalConnectorInfoImpl) connectorInfo, (APIConfigurationImpl) apiConfig);
Class<? extends Connector> connectorClass = connectorOperationalContext.getConnectorClass();
if (connectorClass != null) {
status.setConnectorClassName(connectorClass.getName());
}
ObjectPoolConfiguration poolConfiguration = apiConfig.getConnectorPoolConfiguration();
if (poolConfiguration != null) {
status.setPoolConfigMaxSize(poolConfiguration.getMaxObjects());
status.setPoolConfigMinIdle(poolConfiguration.getMinIdle());
status.setPoolConfigMaxIdle(poolConfiguration.getMaxIdle());
status.setPoolConfigWaitTimeout(poolConfiguration.getMaxWait());
status.setPoolConfigMinEvictableIdleTime(poolConfiguration.getMinEvictableIdleTimeMillis());
status.setPoolConfigMaxIdleTime(poolConfiguration.getMaxIdleTimeMillis());
}
ObjectPool<PoolableConnector> pool = connectorOperationalContext.getPool();
if (pool != null) {
Statistics poolStats = pool.getStatistics();
if (poolStats != null) {
status.setPoolStatusNumActive(poolStats.getNumActive());
status.setPoolStatusNumIdle(poolStats.getNumIdle());
}
}
return status;
}
Aggregations