com.unboundid.directory.sdk.sync.scripting.ScriptedJDBCSyncDestination 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.sql.SQLException;
import java.util.List;
import com.unboundid.directory.sdk.common.internal.Configurable;
import com.unboundid.directory.sdk.sync.config.JDBCSyncDestinationConfig;
import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
import com.unboundid.directory.sdk.sync.types.SyncOperation;
import com.unboundid.directory.sdk.sync.types.SyncServerContext;
import com.unboundid.directory.sdk.sync.types.TransactionContext;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.Modification;
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
* in order to synchronize data into a relational database. Since the UnboundID
* ${SYNC_SERVER_BASE_NAME} is LDAP-centric,
* this API allows you to take LDAP entries and split them out into
* database content and make the appropriate updates. The lifecycle of a sync
* operation is as follows:
*
* - Detect change at the synchronization source
* - Fetch full source entry
* - Perform any mappings and compute the equivalent destination entry
* - Fetch full destination entry
* - Diff the computed destination entry and actual destination entry
* - Apply the minimal set of changes at the destination to bring it in sync
*
*
* This implies that the {@link #fetchEntry(TransactionContext, Entry,
* SyncOperation)} method will
* always be called once prior to any of the other methods in this class.
*
* In several places a {@link TransactionContext} is provided, which allows
* controlled access to the target database. By default, methods in this class
* are always provided with a fresh connection (i.e. a new transaction), and the
* ${SYNC_SERVER_BASE_NAME} will always commit or rollback the transaction
* automatically, depending on whether the method returned normally or threw an
* exception. Implementers may optionally perform their own transaction
* management within these methods if necessary.
*
* Several of these methods throw {@link SQLException}, which should be used in
* the case of any database access error. For other types of errors, runtime
* exceptions may be used (IllegalStateException, NullPointerException, etc.).
* The ${SYNC_SERVER_BASE_NAME} will automatically retry operations that fail,
* up to a configurable amount of attempts. The exception to this rule is if a
* SQLException is thrown with a SQL state string beginning with "08"; this
* indicates a connection error, and in this case the operation is retried
* indefinitely.
*
*
Configuring Groovy-Scripted JDBC Sync Destinations
* In order to configure a scripted JDBC sync destination based on this API and
* written in the Groovy scripting language, use a command like:
*
* dsconfig create-sync-destination \
* --destination-name "{destination-name}" \
* --type groovy-scripted-jdbc \
* --set "server:{server-name}" \
* --set "script-class:{class-name}" \
* --set "script-argument:{name=value}"
*
* where "{destination-name}" is the name to use for the JDBC sync
* destination instance, "{server-name}" is the name of the JDBC external
* server that will be used as the sync destination, "{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 JDBC sync destination. If multiple arguments should be
* provided to the JDBC sync destination, then the
* "--set script-argument:{name=value}
" option should be
* provided multiple times.
*/
@Extensible()
@SynchronizationServerExtension(appliesToLocalContent=false,
appliesToSynchronizedContent=true)
public abstract class ScriptedJDBCSyncDestination implements Configurable
{
/**
* {@inheritDoc}
*/
public void defineConfigArguments(final ArgumentParser parser)
throws ArgumentException
{
// No arguments will be allowed by default.
}
/**
* This hook is called when a Sync Pipe first starts up, or when the Resync
* process first starts up. Any initialization should be performed here.
*
* A {@link TransactionContext} is provided, which allows
* controlled access to the target database. The context will contain a fresh
* fresh connection (i.e. a new transaction), and the ${SYNC_SERVER_BASE_NAME}
* will always commit or rollback the transaction automatically, depending on
* whether this method returns normally or throws an exception. Implementers
* may optionally perform their own transaction management within this method
* if necessary.
*
* The default implementation is empty.
*
* @param ctx
* a TransactionContext which provides a valid JDBC connection to the
* database.
* @param serverContext A handle to the server context for the server in
* which this extension is running.
* @param config The general configuration for this sync destination.
* @param parser The argument parser which has been initialized from
* the configuration for this JDBC sync destination.
*/
@ThreadSafety(level = ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
public void initializeJDBCSyncDestination(
final TransactionContext ctx,
final SyncServerContext serverContext,
final JDBCSyncDestinationConfig config,
final ArgumentParser parser)
{
// No initialization will be performed by default.
}
/**
* This hook is called when a Sync Pipe shuts down, or when the Resync process
* shuts down. Any clean-up should be performed here.
*
* A {@link TransactionContext} is provided, which allows
* controlled access to the target database. The context will contain a fresh
* fresh connection (i.e. a new transaction), and the ${SYNC_SERVER_BASE_NAME}
* will always commit or rollback the transaction automatically, depending on
* whether this method returns normally or throws an exception. Implementers
* may optionally perform their own transaction management within this method
* if necessary.
*
* The default implementation is empty.
*
* @param ctx
* a TransactionContext which provides a valid JDBC connection to the
* database.
*/
@ThreadSafety(level = ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
public void finalizeJDBCSyncDestination(
final TransactionContext ctx)
{
//no implementation required
}
/**
* Return a full destination entry (in LDAP form) from the database,
* corresponding to the source {@link Entry} that is passed in. This
* method should perform any queries necessary to gather the latest values for
* all the attributes to be synchronized and return them in an Entry.
*
* Note that the if the source entry was renamed (see
* {@link SyncOperation#isModifyDN}), the destEntryMappedFromSrc
* will have the new DN; the old DN can be obtained by calling
* {@link SyncOperation#getDestinationEntryBeforeChange()} and getting the DN
* from there. This method should return the entry in its existing form
* (i.e. with the old DN, before it is changed).
*
* A {@link TransactionContext} is provided, which allows
* controlled access to the target database. The context will contain a fresh
* fresh connection (i.e. a new transaction), and the ${SYNC_SERVER_BASE_NAME}
* will always commit or rollback the transaction automatically, depending on
* whether this method returns normally or throws an exception. Implementers
* may optionally perform their own transaction management within this method
* if necessary.
*
* This method must be thread safe, as it will be called repeatedly and
* concurrently by each of the Sync Pipe worker threads as they process
* entries.
*
* @param ctx
* a TransactionContext which provides a valid JDBC connection to the
* database.
* @param destEntryMappedFromSrc
* the LDAP entry which corresponds to the database
* "entry" to fetch
* @param operation
* the sync operation for this change
* @return a full LDAP Entry, or null if no such entry exists.
* @throws SQLException
* if there is an error fetching the entry
*/
@ThreadSafety(level = ThreadSafetyLevel.METHOD_THREADSAFE)
public abstract Entry fetchEntry(final TransactionContext ctx,
final Entry destEntryMappedFromSrc,
final SyncOperation operation)
throws SQLException;
/**
* Creates a full database "entry", corresponding to the LDAP
* {@link Entry} that is passed in. This method should perform any inserts and
* updates necessary to make sure the entry is fully created on the database.
*
* A {@link TransactionContext} is provided, which allows
* controlled access to the target database. The context will contain a fresh
* fresh connection (i.e. a new transaction), and the ${SYNC_SERVER_BASE_NAME}
* will always commit or rollback the transaction automatically, depending on
* whether this method returns normally or throws an exception. Implementers
* may optionally perform their own transaction management within this method
* if necessary.
*
* This method must be thread safe, as it will be called repeatedly and
* concurrently by the Sync Pipe worker threads as they process CREATE
* operations.
*
* @param ctx
* a TransactionContext which provides a valid JDBC connection to the
* database.
* @param entryToCreate
* the LDAP entry which corresponds to the database "entry" to create
* @param operation
* the sync operation for this change
* @throws SQLException
* if there is an error creating the entry
*/
@ThreadSafety(level = ThreadSafetyLevel.METHOD_THREADSAFE)
public abstract void createEntry(final TransactionContext ctx,
final Entry entryToCreate,
final SyncOperation operation)
throws SQLException;
/**
* Modify an "entry" in the database, corresponding to the LDAP
* {@link Entry} that is passed in. This method may perform multiple updates
* (including inserting or deleting rows) in order to fully synchronize the
* entire entry on the database.
*
* Note that the if the source entry was renamed (see
* {@link SyncOperation#isModifyDN}), the
* fetchedDestEntry
will have the old DN; the new DN can
* be obtained by calling
* {@link SyncOperation#getDestinationEntryAfterChange()} and getting the DN
* from there.
*
* A {@link TransactionContext} is provided, which allows
* controlled access to the target database. The context will contain a fresh
* fresh connection (i.e. a new transaction), and the ${SYNC_SERVER_BASE_NAME}
* will always commit or rollback the transaction automatically, depending on
* whether this method returns normally or throws an exception. Implementers
* may optionally perform their own transaction management within this method
* if necessary.
*
* This method must be thread safe, as it will be called repeatedly and
* concurrently by the Sync Pipe worker threads as they process MODIFY
* operations.
*
* @param ctx
* a TransactionContext which provides a valid JDBC connection to the
* database.
* @param fetchedDestEntry
* the LDAP entry which corresponds to the database "entry" to modify
* @param modsToApply
* a list of Modification objects which should be applied
* @param operation
* the sync operation for this change
* @throws SQLException
* if there is an error modifying the entry
*/
@ThreadSafety(level = ThreadSafetyLevel.METHOD_THREADSAFE)
public abstract void modifyEntry(final TransactionContext ctx,
final Entry fetchedDestEntry,
final List modsToApply,
final SyncOperation operation)
throws SQLException;
/**
* Delete a full "entry" from the database, corresponding to the LDAP
* {@link Entry} that is passed in. This method may perform multiple deletes
* or updates if necessary to fully delete the entry from the database.
*
* A {@link TransactionContext} is provided, which allows
* controlled access to the target database. The context will contain a fresh
* fresh connection (i.e. a new transaction), and the ${SYNC_SERVER_BASE_NAME}
* will always commit or rollback the transaction automatically, depending on
* whether this method returns normally or throws an exception. Implementers
* may optionally perform their own transaction management within this method
* if necessary.
*
* This method must be thread safe, as it will be called repeatedly and
* concurrently by the Sync Pipe worker threads as they process DELETE
* operations.
*
* @param ctx
* a TransactionContext which provides a valid JDBC connection to the
* database.
* @param fetchedDestEntry
* the LDAP entry which corresponds to the database "entry" to delete
* @param operation
* the sync operation for this change
* @throws SQLException
* if there is an error deleting the entry
*/
@ThreadSafety(level = ThreadSafetyLevel.METHOD_THREADSAFE)
public abstract void deleteEntry(final TransactionContext ctx,
final Entry fetchedDestEntry,
final SyncOperation operation)
throws SQLException;
}