com.unboundid.directory.sdk.sync.scripting.ScriptedLDAPSyncDestinationPlugin Maven / Gradle / Ivy
Show all versions of server-sdk Show documentation
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* docs/licenses/cddl.txt
* or http://www.opensource.org/licenses/cddl1.php.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* docs/licenses/cddl.txt. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Portions Copyright 2010-2024 Ping Identity Corporation
*/
package com.unboundid.directory.sdk.sync.scripting;
import java.util.List;
import com.unboundid.directory.sdk.common.internal.Reconfigurable;
import com.unboundid.directory.sdk.sync.config.LDAPSyncDestinationPluginConfig;
import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
import com.unboundid.directory.sdk.sync.types.PostStepResult;
import com.unboundid.directory.sdk.sync.types.PreStepResult;
import com.unboundid.directory.sdk.sync.types.SyncOperation;
import com.unboundid.directory.sdk.sync.types.SyncServerContext;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPInterface;
import com.unboundid.ldap.sdk.Modification;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchRequest;
import com.unboundid.ldap.sdk.UpdatableLDAPRequest;
import com.unboundid.util.Extensible;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;
/**
* This class defines an API that must be implemented by scripted extensions
* that perform processing on synchronization operations within an LDAP Sync
* Destination. These extensions may be used to
*
* - Filter out certain changes from being synchronized.
* - Change how an entry is fetched.
* - Change how an entry is modified or created.
*
*
* A note on exception handling: in general subclasses should not
* catch LDAPExceptions that are thrown when using the provided
* LDAPInterface unless there are specific exceptions that are
* expected. The ${SYNC_SERVER_BASE_NAME} will handle
* LDAPExceptions in an appropriate way based on the specific
* cause of the exception. For example, some errors will result
* in the SyncOperation being retried, and others will trigger
* fail over to a different server.
*
* Configuring Groovy-Scripted LDAP Sync Destination Plugins
* In order to configure a scripted LDAP sync destination plugin based on this
* API and written in the Groovy scripting language, use a command like:
*
* dsconfig create-sync-destination-plugin \
* --plugin-name "{plugin-name}" \
* --type groovy-scripted-ldap \
* --set "script-class:{class-name}" \
* --set "script-argument:{name=value}"
*
* where "{plugin-name}" is the name to use for the LDAP sync destination
* plugin instance, "{class-name}" is the fully-qualified name of the
* Groovy class written using this API, and "{name=value}" represents
* name-value pairs for any arguments to provide to the LDAP sync destination
* plugin. If multiple arguments should be provided to the LDAP sync
* destination plugin, then the
* "--set script-argument:{name=value}
" option should be
* provided multiple times.
*
* @see com.unboundid.directory.sdk.sync.api.LDAPSyncDestinationPlugin
*/
@Extensible()
@SynchronizationServerExtension(appliesToLocalContent=false,
appliesToSynchronizedContent=true)
@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
public abstract class ScriptedLDAPSyncDestinationPlugin
implements Reconfigurable
{
/**
* Creates a new instance of this LDAP sync destination plugin. All sync
* destination implementations must include a default constructor, but any
* initialization should generally be done in the
* {@code initializeLDAPSyncDestinationPlugin} method.
*/
public ScriptedLDAPSyncDestinationPlugin()
{
// No implementation is required.
}
/**
* {@inheritDoc}
*/
public void defineConfigArguments(final ArgumentParser parser)
throws ArgumentException
{
// No arguments will be allowed by default.
}
/**
* Initializes this LDAP sync destination plugin.
*
* @param serverContext A handle to the server context for the server in
* which this extension is running.
* @param config The general configuration for this LDAP sync
* destination plugin transformation.
* @param parser The argument parser which has been initialized from
* the configuration for this LDAP sync destination
* plugin.
*
* @throws LDAPException If a problem occurs while initializing this LDAP
* sync destination plugin.
*/
public void initializeLDAPSyncDestinationPlugin(
final SyncServerContext serverContext,
final LDAPSyncDestinationPluginConfig config,
final ArgumentParser parser)
throws LDAPException
{
// No initialization will be performed by default.
}
/**
* Performs any cleanup which may be necessary when this LDAP sync destination
* plugin is to be taken out of service.
*/
public void finalizeLDAPSyncDestinationPlugin()
{
// No implementation is required.
}
/**
* {@inheritDoc}
*/
public boolean isConfigurationAcceptable(
final LDAPSyncDestinationPluginConfig config,
final ArgumentParser parser,
final List unacceptableReasons)
{
// No extended validation will be performed.
return true;
}
/**
* {@inheritDoc}
*/
public ResultCode applyConfiguration(
final LDAPSyncDestinationPluginConfig config,
final ArgumentParser parser,
final List adminActionsRequired,
final List messages)
{
// By default, no configuration changes will be applied.
return ResultCode.SUCCESS;
}
/**
* This method is called before a destination entry is fetched. A
* connection to the destination server is provided along with the
* {@code SearchRequest} that will be sent to the server. This method is
* overridden by plugins that need to have access to the search request
* before it is sent to the destination server. This includes updating the
* search request as well as performing the search instead of the core server,
* including doing additional searches. For plugins that need to manipulate
* the entries that the core LDAP Sync Destination code retrieves from the
* destination, implementing the {@link #postFetch} method is more natural.
*
* This method might be called multiple times for a single synchronization
* operation, specifically when there are multiple search criteria or
* multiple base DNs defined for the Sync Destination.
*
* @param destinationConnection A connection to the destination server.
* @param searchRequest The search request that the LDAP Sync
* Destination will use to fetch the entry.
* @param fetchedEntries A list of entries that have been fetched.
* When the search criteria matches multiple
* entries, they should all be returned. A
* plugin that wishes to implement the fetch
* should put the fetched entries here and
* return
* {@code PreStepResult#SKIP_CURRENT_STEP}.
* @param operation The synchronization operation for this
* change.
*
* @return The result of the plugin processing. Note:
* {@code PreStepResult#SKIP_CURRENT_STEP} should only be returned
* if this plugin takes responsibility for fully fetching the entry
* according to the search request and for populating the
* fetched entry list.
*
* @throws LDAPException In general subclasses should not catch
* LDAPExceptions that are thrown when
* using the LDAPInterface unless there
* are specific exceptions that are
* expected. The ${SYNC_SERVER_BASE_NAME}
* will handle LDAPExceptions in an
* appropriate way based on the specific
* cause of the exception. For example,
* some errors will result in the
* SyncOperation being retried, and others
* will trigger fail over to a different
* server. Plugins should only throw
* LDAPException for errors related to
* communication with the LDAP server.
* Use the return code to indicate other
* types of errors, which might require
* retry.
*/
public PreStepResult preFetch(final LDAPInterface destinationConnection,
final SearchRequest searchRequest,
final List fetchedEntries,
final SyncOperation operation)
throws LDAPException
{
return PreStepResult.CONTINUE;
}
/**
* This method is called after an attempt to fetch a destination entry. An
* connection to the destination server is provided along with the
* {@code SearchRequest} that was sent to the server. This method is
* overridden by plugins that need to manipulate the search results that
* are returned to the Sync Pipe. This can include filtering out certain
* entries, remove information from the entries, or adding additional
* information, possibly by doing a followup LDAP search.
*
* This method might be called multiple times for a single synchronization
* operation, specifically when there are multiple search criteria or
* multiple base DNs defined for the Sync Destination.
*
* This method will not be called if the search fails, for instance, if
* the base DN of the search does not exist.
*
* @param destinationConnection A connection to the destination server.
* @param searchRequest The search request that the LDAP Sync
* Destination used to fetch the entry.
* @param fetchedEntries A list of entries that have been fetched.
* When the search criteria matches multiple
* entries, they will all be returned. Entries
* in this list can be edited directly, and the
* list can be edited as well.
* @param operation The synchronization operation for this
* change.
*
* @return The result of the plugin processing.
*
* @throws LDAPException In general subclasses should not catch
* LDAPExceptions that are thrown when
* using the LDAPInterface unless there
* are specific exceptions that are
* expected. The ${SYNC_SERVER_BASE_NAME}
* will handle LDAPExceptions in an
* appropriate way based on the specific
* cause of the exception. For example,
* some errors will result in the
* SyncOperation being retried, and others
* will trigger fail over to a different
* server. Plugins should only throw
* LDAPException for errors related to
* communication with the LDAP server.
* Use the return code to indicate other
* types of errors, which might require
* retry.
*/
public PostStepResult postFetch(final LDAPInterface destinationConnection,
final SearchRequest searchRequest,
final List fetchedEntries,
final SyncOperation operation)
throws LDAPException
{
return PostStepResult.CONTINUE;
}
/**
* This method is called before a destination entry is created. A
* connection to the destination server is provided along with the
* {@code Entry} that will be sent to the server. This method is
* overridden by plugins that need to alter the entry before it is created
* at the server.
*
* @param destinationConnection A connection to the destination server.
* @param entryToCreate The entry that will be created at the
* destination. A plugin that wishes to
* create the entry should be sure to return
* {@code PreStepResult#SKIP_CURRENT_STEP}.
* @param operation The synchronization operation for this
* change.
*
* @return The result of the plugin processing.
*
* @throws LDAPException In general subclasses should not catch
* LDAPExceptions that are thrown when
* using the LDAPInterface unless there
* are specific exceptions that are
* expected. The ${SYNC_SERVER_BASE_NAME}
* will handle LDAPExceptions in an
* appropriate way based on the specific
* cause of the exception. For example,
* some errors will result in the
* SyncOperation being retried, and others
* will trigger fail over to a different
* server. Plugins should only throw
* LDAPException for errors related to
* communication with the LDAP server.
* Use the return code to indicate other
* types of errors, which might require
* retry.
*/
public PreStepResult preCreate(final LDAPInterface destinationConnection,
final Entry entryToCreate,
final SyncOperation operation)
throws LDAPException
{
return PreStepResult.CONTINUE;
}
/**
* This method is called before a destination entry is modified. A
* connection to the destination server is provided along with the
* {@code Entry} that will be sent to the server. This method is
* overridden by plugins that need to perform some processing on an entry
* before it is modified.
*
* @param destinationConnection A connection to the destination server.
* @param entryToModify The entry that will be modified at the
* destination. A plugin that wishes to
* modify the entry should be sure to return
* {@code PreStepResult#SKIP_CURRENT_STEP}.
* @param modsToApply A modifiable list of the modifications to
* apply at the server.
* @param operation The synchronization operation for this
* change.
*
* @return The result of the plugin processing.
*
* @throws LDAPException In general subclasses should not catch
* LDAPExceptions that are thrown when
* using the LDAPInterface unless there
* are specific exceptions that are
* expected. The ${SYNC_SERVER_BASE_NAME}
* will handle LDAPExceptions in an
* appropriate way based on the specific
* cause of the exception. For example,
* some errors will result in the
* SyncOperation being retried, and others
* will trigger fail over to a different
* server. Plugins should only throw
* LDAPException for errors related to
* communication with the LDAP server.
* Use the return code to indicate other
* types of errors, which might require
* retry.
*/
public PreStepResult preModify(final LDAPInterface destinationConnection,
final Entry entryToModify,
final List modsToApply,
final SyncOperation operation)
throws LDAPException
{
return PreStepResult.CONTINUE;
}
/**
* This method is called before a destination entry is deleted. A
* connection to the destination server is provided along with the
* {@code Entry} that will be sent to the server. This method is
* overridden by plugins that need to perform some processing on an entry
* before it is deleted. A plugin could choose to mark an entry as disabled
* instead of deleting it for instance, or move the entry to a different
* part of the directory hierarchy.
*
* @param destinationConnection A connection to the destination server.
* @param entryToDelete The entry that will be deleted at the
* destination. A plugin that wishes to
* delete the entry should be sure to return
* {@code PreStepResult#SKIP_CURRENT_STEP}.
* @param operation The synchronization operation for this
* change.
*
* @return The result of the plugin processing.
*
* @throws LDAPException In general subclasses should not catch
* LDAPExceptions that are thrown when
* using the LDAPInterface unless there
* are specific exceptions that are
* expected. The ${SYNC_SERVER_BASE_NAME}
* will handle LDAPExceptions in an
* appropriate way based on the specific
* cause of the exception. For example,
* some errors will result in the
* SyncOperation being retried, and others
* will trigger fail over to a different
* server. Plugins should only throw
* LDAPException for errors related to
* communication with the LDAP server.
* Use the return code to indicate other
* types of errors, which might require
* retry.
*/
public PreStepResult preDelete(final LDAPInterface destinationConnection,
final Entry entryToDelete,
final SyncOperation operation)
throws LDAPException
{
return PreStepResult.CONTINUE;
}
/**
* This method is called prior to executing any add, modify, delete, or
* search from the destination but after the respective pre method (e.g
* preFetch or preModify). A connection to the destination server is provided
* along with the {@code UpdatableLDAPRequest} that will be sent to the
* server. this method is overridden by plugins that need to modify the
* LDAP request prior to execution. For example, attaching a {@code Control}
* to the request. Callers of this method can use {@code instanceof}
* to determine which type of LDAP request is being made.
*
* @param destinationConnection A connection to the destination server.
* @param request The LDAP request that will be sent to
* the destination server.
* @param operation The synchronization operation for this
* change.
*
* @return The result of the plugin processing. Be very careful when
* returning {@code PreStepResult#RETRY_OPERATION_UNLIMITED} as this
* can stall all in flight operations until this operation completes.
* This return value should only be used in situations where a
* remote service (e.g., the LDAP server) is unavailable. In this
* case, it's preferable to just throw the underlying LDAPException,
* which the ${SYNC_SERVER_BASE_NAME} will handle correctly based on
* the type of the operation.
*
* @throws LDAPException In general subclasses should not catch
* LDAPExceptions that are thrown when
* using the LDAPInterface unless there
* are specific exceptions that are
* expected. The ${SYNC_SERVER_BASE_NAME}
* will handle LDAPExceptions in an
* appropriate way based on the specific
* cause of the exception. For example,
* some errors will result in the
* SyncOperation being retried, and others
* will trigger fail over to a different
* server. Plugins should only throw
* LDAPException for errors related to
* communication with the LDAP server.
* Use the return code to indicate other
* types of errors, which might require
* retry.
*/
public PreStepResult transformRequest(
final LDAPInterface destinationConnection,
final UpdatableLDAPRequest request,
final SyncOperation operation)
throws LDAPException
{
return PreStepResult.CONTINUE;
}
}