Skip to content

Commit

Permalink
[BASE-92] Introducing live sync #resolve
Browse files Browse the repository at this point in the history
  • Loading branch information
ilgrosso committed Nov 20, 2024
1 parent 4b07e29 commit 21dfc9f
Show file tree
Hide file tree
Showing 30 changed files with 931 additions and 345 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.identityconnectors.framework.api.operations.APIOperation;
import org.identityconnectors.framework.api.operations.ResolveUsernameApiOp;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.LiveSyncResultsHandler;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.ObjectClassInfo;
import org.identityconnectors.framework.common.objects.OperationOptionInfo;
Expand All @@ -30,6 +31,7 @@
import org.identityconnectors.framework.spi.operations.DeleteOp;
import org.identityconnectors.framework.spi.operations.SchemaOp;
import org.identityconnectors.framework.spi.operations.SearchOp;
import org.identityconnectors.framework.spi.operations.LiveSyncOp;
import org.identityconnectors.framework.spi.operations.SyncOp;
import org.identityconnectors.framework.spi.operations.TestOp;
import org.identityconnectors.framework.spi.operations.UpdateAttributeValuesOp;
Expand All @@ -42,7 +44,7 @@
@ConnectorClass(configurationClass = SampleConfiguration.class, displayNameKey = "sample.connector.display")
public class SampleConnector implements Connector,
CreateOp, UpdateOp, UpdateAttributeValuesOp, DeleteOp,
AuthenticateOp, ResolveUsernameApiOp, SchemaOp, SyncOp, TestOp, SearchOp<SampleFilter> {
AuthenticateOp, ResolveUsernameApiOp, SchemaOp, SyncOp, LiveSyncOp, TestOp, SearchOp<SampleFilter> {

private static final Log LOG = Log.getLog(SampleConnector.class);

Expand Down Expand Up @@ -146,6 +148,13 @@ public void sync(
final OperationOptions options) {
}

@Override
public void livesync(
final ObjectClass objectClass,
final LiveSyncResultsHandler handler,
final OperationOptions options) {
}

@Override
public SyncToken getLatestSyncToken(final ObjectClass objectClass) {
return new SyncToken(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* ====================
* Portions Copyrighted 2010-2013 ForgeRock AS.
* Portions Copyrighted 2014-2018 Evolveum
* Portions Copyrighted 2015-2018 ConnId
* Portions Copyrighted 2015-2024 ConnId
*/
package org.identityconnectors.framework.impl.api;

Expand Down Expand Up @@ -130,7 +130,9 @@ public final Schema schema() {
* {@inheritDoc}
*/
@Override
public final Uid create(final ObjectClass objectClass, final Set<Attribute> createAttributes,
public final Uid create(
final ObjectClass objectClass,
final Set<Attribute> createAttributes,
final OperationOptions options) {

return ((CreateApiOp) getOperationCheckSupported(CreateApiOp.class)).
Expand All @@ -150,13 +152,14 @@ public final void delete(final ObjectClass objectClass, final Uid uid, final Ope
*/
@Override
public final SearchResult search(final ObjectClass objectClass, final Filter filter,
ResultsHandler handler, final OperationOptions options) {
final ResultsHandler handler, final OperationOptions options) {

ResultsHandler resultsHandler = handler;
if (LoggingProxy.isLoggable()) {
handler = new SearchResultsHandlerLoggingProxy(handler, LOG, null);
resultsHandler = new SearchResultsHandlerLoggingProxy(handler, LOG, null);
}
return ((SearchApiOp) this.getOperationCheckSupported(SearchApiOp.class)).
search(objectClass, filter, handler, options);
search(objectClass, filter, resultsHandler, options);
}

/**
Expand Down Expand Up @@ -289,20 +292,34 @@ public final SyncToken getLatestSyncToken(final ObjectClass objectClass) {
return ((SyncApiOp) this.getOperationCheckSupported(SyncApiOp.class)).getLatestSyncToken(objectClass);
}

/**
* {@inheritDoc}
*/
@Override
public void livesync(
final ObjectClass objectClass,
final LiveSyncResultsHandler handler,
final OperationOptions options) {

((LiveSyncApiOp) this.getOperationCheckSupported(LiveSyncApiOp.class)).livesync(objectClass, handler, options);
}

/**
* {@inheritDoc}
*/
@Override
public final void testPartialConfiguration() {
((DiscoverConfigurationApiOp) this.getOperationCheckSupported(DiscoverConfigurationApiOp.class)).testPartialConfiguration();
((DiscoverConfigurationApiOp) this.getOperationCheckSupported(DiscoverConfigurationApiOp.class)).
testPartialConfiguration();
}

/**
* {@inheritDoc}
*/
@Override
public final Map<String, SuggestedValues> discoverConfiguration() {
return ((DiscoverConfigurationApiOp) this.getOperationCheckSupported(DiscoverConfigurationApiOp.class)).discoverConfiguration();
return ((DiscoverConfigurationApiOp) this.getOperationCheckSupported(DiscoverConfigurationApiOp.class)).
discoverConfiguration();
}

private static final String MSG = "Operation ''{0}'' not supported.";
Expand All @@ -317,7 +334,7 @@ private APIOperation getOperationCheckSupported(final Class<? extends APIOperati
}

@SafeVarargs
private final APIOperation getDeltaOperationCheckSupported(final Class<? extends APIOperation>... apis) {
private APIOperation getDeltaOperationCheckSupported(final Class<? extends APIOperation>... apis) {
// check if this operation is supported.
for (Class<? extends APIOperation> api : apis) {
if (configuration.isSupportedOperation(api)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,8 @@ public ConnectorFacade newInstance(final ConnectorInfo connectorInfo, String con
*/
@Override
public void dispose() {
// Disposal of connector factory means shutdown of all connector pools.
// This is the end. No more connector instances will be created.
// Disposal of connector factory means shutdown of all connector pools.
// This is the end. No more connector instances will be created.
ConnectorPoolManager.shutdown();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
* ====================
* Portions Copyrighted 2024 ConnId
*/

package org.identityconnectors.framework.impl.api;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.identityconnectors.common.logging.Log;
import org.identityconnectors.framework.api.APIConfiguration;
import org.identityconnectors.framework.api.ConnectorFacade;
Expand All @@ -39,8 +38,7 @@ public class ManagedConnectorFacadeFactoryImpl extends ConnectorFacadeFactoryImp
/**
* Cache of the various ConnectorFacades.
*/
private static final ConcurrentMap<String, ConnectorFacade> CACHE =
new ConcurrentHashMap<String, ConnectorFacade>();
private static final ConcurrentMap<String, ConnectorFacade> CACHE = new ConcurrentHashMap<>();

/**
* {@inheritDoc}
Expand Down Expand Up @@ -82,13 +80,12 @@ public void dispose() {
for (ConnectorFacade facade : CACHE.values()) {
if (facade instanceof LocalConnectorFacadeImpl) {
try {
((LocalConnectorFacadeImpl) facade).dispose();
facade.dispose();
} catch (Exception e) {
LOG.warn(e, "Failed to dispose facade: {0}", facade);
}
}
}
CACHE.clear();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* "Portions Copyrighted [year] [name of copyright owner]"
* ====================
* Portions Copyrighted 2010-2014 ForgeRock AS.
* Portions Copyrighted 2024 ConnId
*/
package org.identityconnectors.framework.impl.api.local;

Expand All @@ -37,7 +38,6 @@

/**
* Implements all the methods of the facade.
* <p>
*/
public class LocalConnectorFacadeImpl extends AbstractConnectorFacade {

Expand All @@ -47,11 +47,14 @@ public class LocalConnectorFacadeImpl extends AbstractConnectorFacade {
/**
* Map the API interfaces to their implementation counterparts.
*/
private static final Map<Class<? extends APIOperation>, Constructor<? extends ConnectorAPIOperationRunner>> API_TO_IMPL =
new HashMap<Class<? extends APIOperation>, Constructor<? extends ConnectorAPIOperationRunner>>();
private static final Map<
Class<? extends APIOperation>, Constructor<? extends ConnectorAPIOperationRunner>> API_TO_IMPL =
new HashMap<>();

private static void addImplementation(final Class<? extends APIOperation> inter,
private static void addImplementation(
final Class<? extends APIOperation> inter,
final Class<? extends ConnectorAPIOperationRunner> impl) {

Constructor<? extends ConnectorAPIOperationRunner> constructor;
try {
constructor = impl.getConstructor(ConnectorOperationalContext.class, Connector.class);
Expand All @@ -75,13 +78,13 @@ private static void addImplementation(final Class<? extends APIOperation> inter,
addImplementation(ScriptOnConnectorApiOp.class, ScriptOnConnectorImpl.class);
addImplementation(ScriptOnResourceApiOp.class, ScriptOnResourceImpl.class);
addImplementation(SyncApiOp.class, SyncImpl.class);
addImplementation(LiveSyncApiOp.class, LiveSyncImpl.class);
addImplementation(DiscoverConfigurationApiOp.class, DiscoverConfigurationImpl.class);
}

// =======================================================================
// Fields
// =======================================================================

/**
* The connector info
*/
Expand All @@ -95,28 +98,26 @@ private static void addImplementation(final Class<? extends APIOperation> inter,
/**
* Builds up the maps of supported operations and calls.
*/
public LocalConnectorFacadeImpl(final LocalConnectorInfoImpl connectorInfo,
public LocalConnectorFacadeImpl(
final LocalConnectorInfoImpl connectorInfo,
final APIConfigurationImpl apiConfiguration) {

super(apiConfiguration);
this.connectorInfo = connectorInfo;
if (connectorInfo.isConfigurationStateless()
&& !connectorInfo.isConnectorPoolingSupported()) {
if (connectorInfo.isConfigurationStateless() && !connectorInfo.isConnectorPoolingSupported()) {
operationalContext = null;
} else {
operationalContext =
new ConnectorOperationalContext(connectorInfo, getAPIConfiguration());
operationalContext = new ConnectorOperationalContext(connectorInfo, getAPIConfiguration());
}
}

public LocalConnectorFacadeImpl(final LocalConnectorInfoImpl connectorInfo, String configuration) {
super(configuration, connectorInfo);
this.connectorInfo = connectorInfo;
if (connectorInfo.isConfigurationStateless()
&& !connectorInfo.isConnectorPoolingSupported()) {
if (connectorInfo.isConfigurationStateless() && !connectorInfo.isConnectorPoolingSupported()) {
operationalContext = null;
} else {
operationalContext =
new ConnectorOperationalContext(connectorInfo, getAPIConfiguration());
operationalContext = new ConnectorOperationalContext(connectorInfo, getAPIConfiguration());
}
}

Expand All @@ -137,22 +138,16 @@ protected ConnectorOperationalContext getOperationalContext() {
// =======================================================================
// ConnectorFacade Interface
// =======================================================================

@Override
protected APIOperation getOperationImplementation(final Class<? extends APIOperation> api) {

APIOperation proxy;
// first create the inner proxy - this is the proxy that obtaining
// a connector from the pool, etc
// NOTE: we want to skip this part of the proxy for
// validate op, but we will want the timeout proxy
// first create the inner proxy - this is the proxy that obtaining a connector from the pool, etc
// NOTE: we want to skip this part of the proxy for validate op, but we will want the timeout proxy
if (api == ValidateApiOp.class) {
final OperationalContext context =
new OperationalContext(connectorInfo, getAPIConfiguration());
final OperationalContext context = new OperationalContext(connectorInfo, getAPIConfiguration());
proxy = new ValidateImpl(context);
} else if (api == GetApiOp.class) {
final Constructor<? extends APIOperationRunner> constructor =
API_TO_IMPL.get(SearchApiOp.class);
final Constructor<? extends APIOperationRunner> constructor = API_TO_IMPL.get(SearchApiOp.class);
final ConnectorAPIOperationRunnerProxy handler =
new ConnectorAPIOperationRunnerProxy(getOperationalContext(), constructor);
proxy = new GetImpl((SearchApiOp) newAPIOperationProxy(SearchApiOp.class, handler));
Expand All @@ -164,9 +159,8 @@ protected APIOperation getOperationImplementation(final Class<? extends APIOpera
}

// now proxy to setup the thread-local classloader
proxy =
newAPIOperationProxy(api, new ThreadClassLoaderManagerProxy(connectorInfo
.getConnectorClass().getClassLoader(), proxy));
proxy = newAPIOperationProxy(api, new ThreadClassLoaderManagerProxy(
connectorInfo.getConnectorClass().getClassLoader(), proxy));

// now wrap the proxy in the appropriate timeout proxy
proxy = createTimeoutProxy(api, proxy);
Expand Down
Loading

0 comments on commit 21dfc9f

Please sign in to comment.