All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.directory.sdk.sync.api.ChangeDetector Maven / Gradle / Ivy

Go to download

The UnboundID Server SDK is a library that may be used to develop various types of extensions to Ping Identity server products, including the PingDirectory Server, PingDirectoryProxy Server, PingDataSync Server, PingDataMetrics Server, and PingAuthorize Server.

The newest version!
/*
 * 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 2018-2024 Ping Identity Corporation
 */
package com.unboundid.directory.sdk.sync.api;

import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
import com.unboundid.directory.sdk.common.internal.Reconfigurable;
import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
import com.unboundid.directory.sdk.sync.config.ChangeDetectorConfig;
import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
import com.unboundid.directory.sdk.sync.types.ChangeRecord;
import com.unboundid.directory.sdk.sync.types.EndpointException;
import com.unboundid.directory.sdk.sync.types.SetStartpointOptions;
import com.unboundid.directory.sdk.sync.types.SyncOperation;
import com.unboundid.directory.sdk.sync.types.SyncServerContext;
import com.unboundid.directory.sdk.sync.types.SyncSourceContext;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.util.Extensible;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;

import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * This class defines an API that must be implemented by extensions that
 * detect changes for an LDAP based Sync Source.
 * A Change Detector can be used to
 * 
    *
  • Process logs or other flat files for changes.
  • *
  • Process changes from a Queue (Kafka, RabbitMQ, etc)
  • *
  • Override the standard cn=changelog * based approach for detecting changes.
  • *
*
*

Configuring Change Detectors

* In order to configure a Change Detector created using this API, use a * command like: *
 *    dsconfig create-change-detector \
 *          --detector-name "{detector-name}" \
 *          --type third-party \
 *          --set "extension-class:{class-name}" \
 *          --set "extension-argument:{name=vale}"
 * 
* where "{plugin-name}" is the name to use for the Change Detector * instance, "{class-name}" is the fully-qualified name of the Java * class that extends * {@code com.unboundid.directory.sdk.sync.api.ChangeDetector}, * and "{name=value}" represents name-value pairs for any arguments to * provide to the Change Detector. If multiple arguments should be provided * to the Change Detector, then the * "--set extension-argument:{name=value}" * option should be provided multiple times. */ @Extensible() @SynchronizationServerExtension(appliesToLocalContent = false, appliesToSynchronizedContent = true) public abstract class ChangeDetector implements UnboundIDExtension, Reconfigurable, ExampleUsageProvider { /** * Creates a new instance of this LDAP Change Detector. All Change * Detector implementations must include a default constructor, but any * initialization should generally be done in the * {@code initializeChangeDetector} method. */ public ChangeDetector() { // No implementation is required. } /** * {@inheritDoc} */ @Override public abstract String getExtensionName(); /** * {@inheritDoc} */ @Override public abstract String[] getExtensionDescription(); /** * {@inheritDoc} */ @Override public Map, String> getExamplesArgumentSets() { return Collections.emptyMap(); } /** * {@inheritDoc} */ @Override 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 * set-startpoint subcommand is called from the realtime-sync command * line tool. Any initialization of this change detector should be performed * here. This method should generally store the {@link SyncServerContext} * and {@link SyncSourceContext} in a class member so that it can be used * elsewhere in the implementation. *

* The default implementation is empty. * * @param serverContext A handle to the server context for the server in * which this extension is running. * @param syncSourceContext An interface for interacting with the Sync * Source that owns this Change Detector or * {@code null} if the Change Detector is only * being initialized to validate its configuration. * @param parser The argument parser which has been initialized * from the configuration for this sync source. */ public void initializeChangeDetector( final SyncServerContext serverContext, final SyncSourceContext syncSourceContext, final ArgumentParser parser) { // No initialization will be performed by default. } /** * This hook is called when a Sync Pipe shuts down or when the set-startpoint * subcommand (from the realtime-sync command line tool) is finished. * Any clean up of this change detector should be performed here. *

* The default implementation is empty. */ public void finalizeChangeDetector() { //No implementation required by default. } /** * {@inheritDoc} */ public boolean isConfigurationAcceptable( final ChangeDetectorConfig config, final ArgumentParser parser, final List unacceptableReasons) { // No implementation required by default. return true; } /** * {@inheritDoc} */ public ResultCode applyConfiguration(final ChangeDetectorConfig config, final ArgumentParser parser, final List adminActionsRequired, final List messages) { // No implementation required by default. return ResultCode.SUCCESS; } /** * This method should effectively set the starting point for synchronization * to the place specified by the options parameter. This should * cause all changes previous to the specified start point to be disregarded * and only changes after that point to be returned by * {@link #getNextBatchOfChanges(int, AtomicLong)}. *

* There are several different startpoint types (see * {@link SetStartpointOptions}), and this implementation is not required to * support them all. If the specified startpoint type is unsupported, this * method should throw an {@link UnsupportedOperationException}. * * IMPORTANT: The RESUME_AT_SERIALIZABLE startpoint type * must be supported by your implementation, because this is used when a Sync * Pipe first starts up. The {@link Serializable} in this case is the same * type that is returned by {@link #getStartpoint()}; the Sync Server persists * it and passes it back in on a restart. *

* This method can be called from two different contexts: *

    *
  • When the 'set-startpoint' subcommand of the realtime-sync CLI is used * (the Sync Pipe is required to be stopped in this context)
  • *
  • Immediately after a Sync Pipe starts up and a connection is first * established to the source server (e.g. before the first call to * {@link #getNextBatchOfChanges(int, AtomicLong)})
  • *
* * @param options an object which indicates where exactly to start * synchronizing (e.g. the end of the changelog, specific * change number, a certain time ago, etc) * @throws EndpointException if there is any error while setting the * start point */ public abstract void setStartpoint(final SetStartpointOptions options) throws EndpointException; /** * Gets the current value of the startpoint for change detection. This is the * "bookmark" which indicates which changes have already been processed and * which have not. In most cases, a change number is used to detect changes * and is managed by the ${SYNC_SERVER_BASE_NAME}, in which case this * implementation needs only to return the latest acknowledged * change number. In other cases, the return value may correspond to a * different value, such as the SYS_CHANGE_VERSION in Microsoft SQL Server. * In any case, this method should return the value that is updated by * {@link #acknowledgeCompletedOps(LinkedList)}. *

* This method is called periodically and the return value is saved in the * persistent state for the Sync Pipe that uses this extension as its Sync * Source. * * IMPORTANT: The internal value for the startpoint should only be * updated after a sync operation is acknowledged back to this extension (via * {@link #acknowledgeCompletedOps(LinkedList)}). * Otherwise it will be possible for changes to be missed when the * ${SYNC_SERVER_BASE_NAME} is restarted or a connection error occurs. * * @return a value to store in the persistent state for the Sync Pipe. This is * usually a change number, but if a changelog table is not used to * detect changes, this value should represent some other token to * pass into {@link #setStartpoint(SetStartpointOptions)} * when the sync pipe starts up. */ public abstract Serializable getStartpoint(); /** * Return the next batch of change records from the source. Change records * are usually just hints that a change happened; they do not include * the full contents of the target entry. In an effort to never synchronize * stale data, the ${SYNC_SERVER_BASE_NAME} will go back and fetch the full * target entry for each change record. *

* On the first invocation, this should return changes starting from the * startpoint that was set by * {@link #setStartpoint(SetStartpointOptions)}. This method is also * responsible for updating the internal state such that subsequent * invocations do not return duplicate changes. *

* The resulting list should be limited by maxChanges. The * numStillPending reference should be set to the estimated * number of changes that haven't yet been retrieved from the source endpoint * when this method returns, or zero if all the current changes have been * retrieved. * * IMPORTANT: While this method needs to keep track of which changes * have already been returned so that it does not return them again, it should * NOT modify the official startpoint. The internal value for the * startpoint should only be updated after a sync operation is acknowledged * back to this extension (via * {@link #acknowledgeCompletedOps(LinkedList)}). * Otherwise it will be possible for changes to be missed when the * ${SYNC_SERVER_BASE_NAME} is restarted or a connection error occurs. The * startpoint should not change as a result of this method. *

* This method does not need to be thread-safe. It will be invoked * repeatedly by a single thread, based on the polling interval set in the * Sync Pipe configuration. * * @param maxChanges the maximum number of changes to retrieve * @param numStillPending this should be set to the number of unretrieved * changes that are still pending after this batch has * been retrieved. This will be passed in as zero, and * may be left that way if the actual value cannot be * determined. * @return a list of {@link ChangeRecord} instances, each * corresponding to a single change at the source endpoint. * If there are no new changes to return, this method should return * an empty list. * @throws EndpointException if there is any error while retrieving the * next batch of changes */ public abstract List getNextBatchOfChanges( final int maxChanges, final AtomicLong numStillPending) throws EndpointException; /** * Provides a way for the ${SYNC_SERVER_BASE_NAME} to acknowledge back to the * extension which sync operations it has processed. This method should update * the official startpoint which was set by * {@link #setStartpoint(SetStartpointOptions)} and is * returned by {@link #getStartpoint()}. * * IMPORTANT: The internal value for the startpoint should only be * updated after a sync operation is acknowledged back to this extension (via * this method). Otherwise it will be possible for changes to be missed when * the ${SYNC_SERVER_BASE_NAME} is restarted or a connection error occurs. * * @param completedOps a list of {@link SyncOperation}s that have finished * processing. The records are listed in the order they * were first detected. * @throws EndpointException if there is an error acknowledging the changes * back to the source */ public abstract void acknowledgeCompletedOps( final LinkedList completedOps) throws EndpointException; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy