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 * Copyright 2010-2014 UnboundID Corp. 026 */ 027 package com.unboundid.directory.sdk.sync.api; 028 029 030 031 import java.util.Collections; 032 import java.util.List; 033 import java.util.Map; 034 import java.util.concurrent.atomic.AtomicReference; 035 036 import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider; 037 import com.unboundid.directory.sdk.common.internal.Reconfigurable; 038 import com.unboundid.directory.sdk.common.internal.UnboundIDExtension; 039 import com.unboundid.directory.sdk.sync.config.LDAPSyncSourcePluginConfig; 040 import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension; 041 import com.unboundid.directory.sdk.sync.types.PostStepResult; 042 import com.unboundid.directory.sdk.sync.types.SyncOperation; 043 import com.unboundid.directory.sdk.sync.types.SyncServerContext; 044 import com.unboundid.ldap.sdk.Entry; 045 import com.unboundid.ldap.sdk.LDAPException; 046 import com.unboundid.ldap.sdk.LDAPInterface; 047 import com.unboundid.ldap.sdk.ResultCode; 048 import com.unboundid.util.Extensible; 049 import com.unboundid.util.ThreadSafety; 050 import com.unboundid.util.ThreadSafetyLevel; 051 import com.unboundid.util.args.ArgumentException; 052 import com.unboundid.util.args.ArgumentParser; 053 054 055 056 /** 057 * This class defines an API that must be implemented by extensions that 058 * perform processing on synchronization operations within an LDAP Sync 059 * Source. These extensions may be used to 060 * <ul> 061 * <li>Filter out certain changes from being synchronized.</li> 062 * <li>Change how an entry is fetched.</li> 063 * </ul> 064 * <BR> 065 * A note on exception handling: in general subclasses should not 066 * catch LDAPExceptions that are thrown when using the provided 067 * LDAPInterface unless there are specific exceptions that are 068 * expected. The Synchronization Server will handle 069 * LDAPExceptions in an appropriate way based on the specific 070 * cause of the exception. For example, some errors will result 071 * in the SyncOperation being retried, and others will trigger 072 * fail over to a different server. 073 * <BR> 074 * <H2>Configuring LDAP Sync Source Plugins</H2> 075 * In order to configure an LDAP sync source plugin created using this API, use 076 * a command like: 077 * <PRE> 078 * dsconfig create-sync-source-plugin \ 079 * --plugin-name "<I>{plugin-name}</I>" \ 080 * --type third-party-ldap \ 081 * --set "extension-class:<I>{class-name}</I>" \ 082 * --set "extension-argument:<I>{name=value}</I>" 083 * </PRE> 084 * where "<I>{plugin-name}</I>" is the name to use for the LDAP sync source 085 * plugin instance, "<I>{class-name}</I>" is the fully-qualified name of the 086 * Java class that extends 087 * {@code com.unboundid.directory.sdk.sync.api.LDAPSyncSourcePlugin}, and 088 * "<I>{name=value}</I>" represents name-value pairs for any arguments to 089 * provide to the LDAP sync source plugin. If multiple arguments should be 090 * provided to the LDAP sync source plugin, then the 091 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be 092 * provided multiple times. 093 * 094 * @see com.unboundid.directory.sdk.sync.scripting.ScriptedLDAPSyncSourcePlugin 095 */ 096 @Extensible() 097 @SynchronizationServerExtension(appliesToLocalContent=false, 098 appliesToSynchronizedContent=true) 099 @ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE) 100 public abstract class LDAPSyncSourcePlugin 101 implements UnboundIDExtension, 102 Reconfigurable<LDAPSyncSourcePluginConfig>, 103 ExampleUsageProvider 104 { 105 /** 106 * Creates a new instance of this LDAP sync source plugin. All sync 107 * source implementations must include a default constructor, but any 108 * initialization should generally be done in the 109 * {@code initializeLDAPSyncSourcePlugin} method. 110 */ 111 public LDAPSyncSourcePlugin() 112 { 113 // No implementation is required. 114 } 115 116 117 118 /** 119 * {@inheritDoc} 120 */ 121 public abstract String getExtensionName(); 122 123 124 125 /** 126 * {@inheritDoc} 127 */ 128 public abstract String[] getExtensionDescription(); 129 130 131 132 /** 133 * {@inheritDoc} 134 */ 135 public void defineConfigArguments(final ArgumentParser parser) 136 throws ArgumentException 137 { 138 // No arguments will be allowed by default. 139 } 140 141 142 143 /** 144 * Initializes this LDAP sync source plugin. This method will be called 145 * before any other methods in the class. 146 * 147 * @param serverContext A handle to the server context for the 148 * Synchronization Server in which this extension is 149 * running. Extensions should typically store this 150 * in a class member. 151 * @param config The general configuration for this proxy 152 * transformation. 153 * @param parser The argument parser which has been initialized from 154 * the configuration for this LDAP sync source 155 * plugin. 156 * 157 * @throws LDAPException If a problem occurs while initializing this ldap 158 * sync source plugin. 159 */ 160 public void initializeLDAPSyncSourcePlugin( 161 final SyncServerContext serverContext, 162 final LDAPSyncSourcePluginConfig config, 163 final ArgumentParser parser) 164 throws LDAPException 165 { 166 // No initialization will be performed by default. 167 } 168 169 170 171 /** 172 * {@inheritDoc} 173 */ 174 public boolean isConfigurationAcceptable( 175 final LDAPSyncSourcePluginConfig config, 176 final ArgumentParser parser, 177 final List<String> unacceptableReasons) 178 { 179 // No extended validation will be performed by default. 180 return true; 181 } 182 183 184 185 /** 186 * {@inheritDoc} 187 */ 188 public ResultCode applyConfiguration(final LDAPSyncSourcePluginConfig config, 189 final ArgumentParser parser, 190 final List<String> adminActionsRequired, 191 final List<String> messages) 192 { 193 // By default, no configuration changes will be applied. 194 return ResultCode.SUCCESS; 195 } 196 197 198 199 /** 200 * Performs any cleanup which may be necessary when this LDAP sync source 201 * plugin is taken out of service. This can happen when it is deleted from 202 * the configuration and at server shutdown. 203 */ 204 public void finalizeLDAPSyncSourcePlugin() 205 { 206 // No implementation is required. 207 } 208 209 210 211 /** 212 * This method is called after fetching a source entry. A 213 * connection to the source server is provided. This method is 214 * overridden by plugins that need to manipulate the search results that 215 * are returned to the Sync Pipe. This can include filtering out certain 216 * entries, remove information from the entries, or adding additional 217 * information, possibly by doing a followup LDAP search. 218 * 219 * @param sourceConnection A connection to the source server. 220 * @param fetchedEntryRef A reference to the entry that was fetched. 221 * This entry can be edited in place, or the 222 * reference can be changed to point to a 223 * different entry that the plugin constructs. 224 * @param operation The synchronization operation for this 225 * change. 226 * 227 * @return The result of the plugin processing. 228 * 229 * @throws LDAPException In general subclasses should not catch 230 * LDAPExceptions that are thrown when 231 * using the LDAPInterface unless there 232 * are specific exceptions that are 233 * expected. The Synchronization Server 234 * will handle LDAPExceptions in an 235 * appropriate way based on the specific 236 * cause of the exception. For example, 237 * some errors will result in the 238 * SyncOperation being retried, and others 239 * will trigger fail over to a different 240 * server. Plugins should only throw 241 * LDAPException for errors related to 242 * communication with the LDAP server. 243 * Use the return code to indicate other 244 * types of errors, which might require 245 * retry. 246 */ 247 public PostStepResult postFetch(final LDAPInterface sourceConnection, 248 final AtomicReference<Entry> fetchedEntryRef, 249 final SyncOperation operation) 250 throws LDAPException 251 { 252 return PostStepResult.CONTINUE; 253 } 254 255 256 257 /** 258 * Retrieves a string representation of this LDAP sync source plugin. 259 * 260 * @return A string representation of this LDAP sync source plugin. 261 */ 262 @Override() 263 public final String toString() 264 { 265 final StringBuilder buffer = new StringBuilder(); 266 toString(buffer); 267 return buffer.toString(); 268 } 269 270 271 272 /** 273 * Appends a string representation of this LDAP sync source plugin to the 274 * provided buffer. 275 * 276 * @param buffer The buffer to which the string representation should be 277 * appended. 278 */ 279 public abstract void toString(final StringBuilder buffer); 280 281 282 283 /** 284 * {@inheritDoc} 285 */ 286 public Map<List<String>,String> getExamplesArgumentSets() 287 { 288 return Collections.emptyMap(); 289 } 290 }