001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * docs/licenses/cddl.txt 011 * or http://www.opensource.org/licenses/cddl1.php. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * docs/licenses/cddl.txt. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Portions Copyright 2010-2023 Ping Identity Corporation 026 */ 027package com.unboundid.directory.sdk.sync.scripting; 028 029 030 031import java.util.List; 032import java.util.concurrent.atomic.AtomicReference; 033 034import com.unboundid.directory.sdk.common.internal.Reconfigurable; 035import com.unboundid.directory.sdk.sync.config.LDAPSyncSourcePluginConfig; 036import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension; 037import com.unboundid.directory.sdk.sync.types.PostStepResult; 038import com.unboundid.directory.sdk.sync.types.SyncOperation; 039import com.unboundid.directory.sdk.sync.types.SyncServerContext; 040import com.unboundid.ldap.sdk.Entry; 041import com.unboundid.ldap.sdk.LDAPException; 042import com.unboundid.ldap.sdk.LDAPInterface; 043import com.unboundid.ldap.sdk.ResultCode; 044import com.unboundid.util.Extensible; 045import com.unboundid.util.ThreadSafety; 046import com.unboundid.util.ThreadSafetyLevel; 047import com.unboundid.util.args.ArgumentException; 048import com.unboundid.util.args.ArgumentParser; 049 050 051 052/** 053 * This class defines an API that must be implemented by scripted extensions 054 * that perform processing on synchronization operations within an LDAP Sync 055 * Source. These extensions may be used to 056 * <ul> 057 * <li>Filter out certain changes from being synchronized.</li> 058 * <li>Change how an entry is fetched.</li> 059 * </ul> 060 * <BR> 061 * A note on exception handling: in general subclasses should not 062 * catch LDAPExceptions that are thrown when using the provided 063 * LDAPInterface unless there are specific exceptions that are 064 * expected. The Data Sync Server will handle 065 * LDAPExceptions in an appropriate way based on the specific 066 * cause of the exception. For example, some errors will result 067 * in the SyncOperation being retried, and others will trigger 068 * fail over to a different server. 069 * <BR> 070 * <H2>Configuring Groovy-Scripted LDAP Sync Source Plugins</H2> 071 * In order to configure a scripted LDAP sync source plugin based on this API 072 * and written in the Groovy scripting language, use a command like: 073 * <PRE> 074 * dsconfig create-sync-source-plugin \ 075 * --plugin-name "<I>{plugin-name}</I>" \ 076 * --type groovy-scripted-ldap \ 077 * --set "script-class:<I>{class-name}</I>" \ 078 * --set "script-argument:<I>{name=value}</I>" 079 * </PRE> 080 * where "<I>{plugin-name}</I>" is the name to use for the LDAP sync source 081 * plugin instance, "<I>{class-name}</I>" is the fully-qualified name of the 082 * Groovy class written using this API, and "<I>{name=value}</I>" represents 083 * name-value pairs for any arguments to provide to the LDAP sync source plugin. 084 * If multiple arguments should be provided to the LDAP sync source plugin, then 085 * the "<CODE>--set script-argument:<I>{name=value}</I></CODE>" option should be 086 * provided multiple times. 087 * 088 * @see com.unboundid.directory.sdk.sync.api.LDAPSyncSourcePlugin 089 */ 090@Extensible() 091@SynchronizationServerExtension(appliesToLocalContent=false, 092 appliesToSynchronizedContent=true) 093@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE) 094public abstract class ScriptedLDAPSyncSourcePlugin 095 implements Reconfigurable<LDAPSyncSourcePluginConfig> 096{ 097 /** 098 * Creates a new instance of this LDAP sync source plugin. All sync 099 * source implementations must include a default constructor, but any 100 * initialization should generally be done in the 101 * {@code initializeLDAPSyncSourcePlugin} method. 102 */ 103 public ScriptedLDAPSyncSourcePlugin() 104 { 105 // No implementation is required. 106 } 107 108 109 110 /** 111 * {@inheritDoc} 112 */ 113 public void defineConfigArguments(final ArgumentParser parser) 114 throws ArgumentException 115 { 116 // No arguments will be allowed by default. 117 } 118 119 120 121 /** 122 * Initializes this LDAP sync source plugin. 123 * 124 * @param serverContext A handle to the server context for the server in 125 * which this extension is running. 126 * @param config The general configuration for this LDAP sync 127 * source plugin transformation. 128 * @param parser The argument parser which has been initialized from 129 * the configuration for this LDAP sync source plugin. 130 * 131 * @throws LDAPException If a problem occurs while initializing this LDAP 132 * sync source plugin. 133 */ 134 public void initializeLDAPSyncSourcePlugin( 135 final SyncServerContext serverContext, 136 final LDAPSyncSourcePluginConfig config, 137 final ArgumentParser parser) 138 throws LDAPException 139 { 140 // No initialization will be performed by default. 141 } 142 143 144 145 /** 146 * Performs any cleanup which may be necessary when this LDAP sync source 147 * plugin is to be taken out of service. 148 */ 149 public void finalizeLDAPSyncSourcePlugin() 150 { 151 // No implementation is required. 152 } 153 154 155 156 /** 157 * {@inheritDoc} 158 */ 159 public boolean isConfigurationAcceptable( 160 final LDAPSyncSourcePluginConfig config, 161 final ArgumentParser parser, 162 final List<String> unacceptableReasons) 163 { 164 // No extended validation will be performed. 165 return true; 166 } 167 168 169 170 /** 171 * {@inheritDoc} 172 */ 173 public ResultCode applyConfiguration(final LDAPSyncSourcePluginConfig config, 174 final ArgumentParser parser, 175 final List<String> adminActionsRequired, 176 final List<String> messages) 177 { 178 // By default, no configuration changes will be applied. 179 return ResultCode.SUCCESS; 180 } 181 182 183 184 /** 185 * This method is called after fetching a source entry. A 186 * connection to the source server is provided. This method is 187 * overridden by plugins that need to manipulate the search results that 188 * are returned to the Sync Pipe. This can include filtering out certain 189 * entries, remove information from the entries, or adding additional 190 * information, possibly by doing a followup LDAP search. 191 * 192 * @param sourceConnection A connection to the source server. 193 * @param fetchedEntryRef A reference to the entry that was fetched. 194 * This entry can be edited in place, or the 195 * reference can be changed to point to a 196 * different entry that the plugin constructs. 197 * @param operation The synchronization operation for this 198 * change. 199 * 200 * @return The result of the plugin processing. 201 * 202 * @throws LDAPException In general subclasses should not catch 203 * LDAPExceptions that are thrown when 204 * using the LDAPInterface unless there 205 * are specific exceptions that are 206 * expected. The Data Sync Server 207 * will handle LDAPExceptions in an 208 * appropriate way based on the specific 209 * cause of the exception. For example, 210 * some errors will result in the 211 * SyncOperation being retried, and others 212 * will trigger fail over to a different 213 * server. Plugins should only throw 214 * LDAPException for errors related to 215 * communication with the LDAP server. 216 * Use the return code to indicate other 217 * types of errors, which might require 218 * retry. 219 */ 220 public PostStepResult postFetch(final LDAPInterface sourceConnection, 221 final AtomicReference<Entry> fetchedEntryRef, 222 final SyncOperation operation) 223 throws LDAPException 224 { 225 return PostStepResult.CONTINUE; 226 } 227}