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
035 import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
036 import com.unboundid.directory.sdk.common.internal.Reconfigurable;
037 import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
038 import com.unboundid.directory.sdk.sync.config.LDAPSyncDestinationPluginConfig;
039 import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
040 import com.unboundid.directory.sdk.sync.scripting.
041 ScriptedLDAPSyncDestinationPlugin;
042 import com.unboundid.directory.sdk.sync.types.PostStepResult;
043 import com.unboundid.directory.sdk.sync.types.PreStepResult;
044 import com.unboundid.directory.sdk.sync.types.SyncOperation;
045 import com.unboundid.directory.sdk.sync.types.SyncServerContext;
046 import com.unboundid.ldap.sdk.Entry;
047 import com.unboundid.ldap.sdk.LDAPException;
048 import com.unboundid.ldap.sdk.LDAPInterface;
049 import com.unboundid.ldap.sdk.Modification;
050 import com.unboundid.ldap.sdk.ResultCode;
051 import com.unboundid.ldap.sdk.SearchRequest;
052 import com.unboundid.util.Extensible;
053 import com.unboundid.util.ThreadSafety;
054 import com.unboundid.util.ThreadSafetyLevel;
055 import com.unboundid.util.args.ArgumentException;
056 import com.unboundid.util.args.ArgumentParser;
057
058
059
060 /**
061 * This class defines an API that must be implemented by extensions that
062 * perform processing on synchronization operations within an LDAP Sync
063 * Destination. These extensions may be used to
064 * <ul>
065 * <li>Filter out certain changes from being synchronized.</li>
066 * <li>Change how an entry is fetched.</li>
067 * <li>Change how an entry is modified or created.</li>
068 * </ul>
069 * <BR>
070 * A note on exception handling: in general subclasses should not
071 * catch LDAPExceptions that are thrown when using the provided
072 * LDAPInterface unless there are specific exceptions that are
073 * expected. The Synchronization Server will handle
074 * LDAPExceptions in an appropriate way based on the specific
075 * cause of the exception. For example, some errors will result
076 * in the SyncOperation being retried, and others will trigger
077 * fail over to a different server.
078 * <BR>
079 * <H2>Configuring LDAP Sync Destination Plugins</H2>
080 * In order to configure an LDAP sync destination plugin created using this API,
081 * use a command like:
082 * <PRE>
083 * dsconfig create-sync-destination-plugin \
084 * --plugin-name "<I>{plugin-name}</I>" \
085 * --type third-party-ldap \
086 * --set "extension-class:<I>{class-name}</I>" \
087 * --set "extension-argument:<I>{name=value}</I>"
088 * </PRE>
089 * where "<I>{plugin-name}</I>" is the name to use for the LDAP sync destination
090 * plugin instance, "<I>{class-name}</I>" is the fully-qualified name of the
091 * Java class that extends
092 * {@code com.unboundid.directory.sdk.sync.api.LDAPSyncDestinationPlugin}, and
093 * "<I>{name=value}</I>" represents name-value pairs for any arguments to
094 * provide to the LDAP sync destination plugin. If multiple arguments should be
095 * provided to the LDAP sync destination plugin, then the
096 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
097 * provided multiple times.
098 *
099 * @see ScriptedLDAPSyncDestinationPlugin
100 */
101 @Extensible()
102 @SynchronizationServerExtension(appliesToLocalContent=false,
103 appliesToSynchronizedContent=true)
104 @ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
105 public abstract class LDAPSyncDestinationPlugin
106 implements UnboundIDExtension,
107 Reconfigurable<LDAPSyncDestinationPluginConfig>,
108 ExampleUsageProvider
109 {
110 /**
111 * Creates a new instance of this LDAP sync destination plugin. All sync
112 * destination implementations must include a default constructor, but any
113 * initialization should generally be done in the
114 * {@code initializeLDAPSyncDestinationPlugin} method.
115 */
116 public LDAPSyncDestinationPlugin()
117 {
118 // No implementation is required. However, we need to reference the
119 // scripted LDAP sync destination plugin so that checkstyle is satisfied
120 // with the import.
121 final ScriptedLDAPSyncDestinationPlugin scriptedPlugin = null;
122 }
123
124
125
126 /**
127 * {@inheritDoc}
128 */
129 public abstract String getExtensionName();
130
131
132
133 /**
134 * {@inheritDoc}
135 */
136 public abstract String[] getExtensionDescription();
137
138
139
140 /**
141 * {@inheritDoc}
142 */
143 public void defineConfigArguments(final ArgumentParser parser)
144 throws ArgumentException
145 {
146 // No arguments will be allowed by default.
147 }
148
149
150
151 /**
152 * Initializes this LDAP sync destination plugin. This method will be called
153 * before any other methods in the class.
154 *
155 * @param serverContext A handle to the server context for the
156 * Synchronization Server in which this extension is
157 * running. Extensions should typically store this
158 * in a class member.
159 * @param config The general configuration for this proxy
160 * transformation.
161 * @param parser The argument parser which has been initialized from
162 * the configuration for this LDAP sync destination
163 * plugin.
164 *
165 * @throws LDAPException If a problem occurs while initializing this ldap
166 * sync destination plugin.
167 */
168 public void initializeLDAPSyncDestinationPlugin(
169 final SyncServerContext serverContext,
170 final LDAPSyncDestinationPluginConfig config,
171 final ArgumentParser parser)
172 throws LDAPException
173 {
174 // No initialization will be performed by default.
175 }
176
177
178
179 /**
180 * {@inheritDoc}
181 */
182 public boolean isConfigurationAcceptable(
183 final LDAPSyncDestinationPluginConfig config,
184 final ArgumentParser parser,
185 final List<String> unacceptableReasons)
186 {
187 // No extended validation will be performed by default.
188 return true;
189 }
190
191
192
193 /**
194 * {@inheritDoc}
195 */
196 public ResultCode applyConfiguration(
197 final LDAPSyncDestinationPluginConfig config,
198 final ArgumentParser parser,
199 final List<String> adminActionsRequired,
200 final List<String> messages)
201 {
202 // By default, no configuration changes will be applied.
203 return ResultCode.SUCCESS;
204 }
205
206
207
208 /**
209 * Performs any cleanup which may be necessary when this LDAP sync destination
210 * plugin is taken out of service. This can happen when it is deleted from
211 * the configuration and at server shutdown.
212 */
213 public void finalizeLDAPSyncDestinationPlugin()
214 {
215 // No implementation is required.
216 }
217
218
219
220 /**
221 * This method is called before a destination entry is fetched. A
222 * connection to the destination server is provided along with the
223 * {@code SearchRequest} that will be sent to the server. This method is
224 * overridden by plugins that need to have access to the search request
225 * before it is sent to the destination server. This includes updating the
226 * search request as well as performing the search instead of the core server,
227 * including doing additional searches. For plugins that need to manipulate
228 * the entries that the core LDAP Sync Destination code retrieves from the
229 * destination, implementing the {@link #postFetch} method is more natural.
230 * <p>
231 * This method might be called multiple times for a single synchronization
232 * operation, specifically when there are multiple search criteria or
233 * multiple base DNs defined for the Sync Destination.
234 *
235 * @param destinationConnection A connection to the destination server.
236 * @param searchRequest The search request that the LDAP Sync
237 * Destination will use to fetch the entry.
238 * @param fetchedEntries A list of entries that have been fetched.
239 * When the search criteria matches multiple
240 * entries, they should all be returned. A
241 * plugin that wishes to implement the fetch
242 * should put the fetched entries here and
243 * return
244 * {@code PreStepResult#SKIP_CURRENT_STEP}.
245 * @param operation The synchronization operation for this
246 * change.
247 *
248 * @return The result of the plugin processing. Note:
249 * {@code PreStepResult#SKIP_CURRENT_STEP} should only be returned
250 * if this plugin takes responsibility for fully fetching the entry
251 * according to the search request and for populating the
252 * fetched entry list.
253 *
254 * @throws LDAPException In general subclasses should not catch
255 * LDAPExceptions that are thrown when
256 * using the LDAPInterface unless there
257 * are specific exceptions that are
258 * expected. The Synchronization Server
259 * will handle LDAPExceptions in an
260 * appropriate way based on the specific
261 * cause of the exception. For example,
262 * some errors will result in the
263 * SyncOperation being retried, and others
264 * will trigger fail over to a different
265 * server. Plugins should only throw
266 * LDAPException for errors related to
267 * communication with the LDAP server.
268 * Use the return code to indicate other
269 * types of errors, which might require
270 * retry.
271 */
272 public PreStepResult preFetch(final LDAPInterface destinationConnection,
273 final SearchRequest searchRequest,
274 final List<Entry> fetchedEntries,
275 final SyncOperation operation)
276 throws LDAPException
277 {
278 return PreStepResult.CONTINUE;
279 }
280
281
282
283 /**
284 * This method is called after an attempt to fetch a destination entry. An
285 * connection to the destination server is provided along with the
286 * {@code SearchRequest} that was sent to the server. This method is
287 * overridden by plugins that need to manipulate the search results that
288 * are returned to the Sync Pipe. This can include filtering out certain
289 * entries, remove information from the entries, or adding additional
290 * information, possibly by doing a followup LDAP search.
291 * <p>
292 * This method might be called multiple times for a single synchronization
293 * operation, specifically when there are multiple search criteria or
294 * multiple base DNs defined for the Sync Destination.
295 * <p>
296 * This method will not be called if the search fails, for instance, if
297 * the base DN of the search does not exist.
298 *
299 * @param destinationConnection A connection to the destination server.
300 * @param searchRequest The search request that the LDAP Sync
301 * Destination used to fetch the entry.
302 * @param fetchedEntries A list of entries that have been fetched.
303 * When the search criteria matches multiple
304 * entries, they will all be returned. Entries
305 * in this list can be edited directly, and the
306 * list can be edited as well.
307 * @param operation The synchronization operation for this
308 * change.
309 *
310 * @return The result of the plugin processing.
311 *
312 * @throws LDAPException In general subclasses should not catch
313 * LDAPExceptions that are thrown when
314 * using the LDAPInterface unless there
315 * are specific exceptions that are
316 * expected. The Synchronization Server
317 * will handle LDAPExceptions in an
318 * appropriate way based on the specific
319 * cause of the exception. For example,
320 * some errors will result in the
321 * SyncOperation being retried, and others
322 * will trigger fail over to a different
323 * server. Plugins should only throw
324 * LDAPException for errors related to
325 * communication with the LDAP server.
326 * Use the return code to indicate other
327 * types of errors, which might require
328 * retry.
329 */
330 public PostStepResult postFetch(final LDAPInterface destinationConnection,
331 final SearchRequest searchRequest,
332 final List<Entry> fetchedEntries,
333 final SyncOperation operation)
334 throws LDAPException
335 {
336 return PostStepResult.CONTINUE;
337 }
338
339
340
341 /**
342 * This method is called before a destination entry is created. A
343 * connection to the destination server is provided along with the
344 * {@code Entry} that will be sent to the server. This method is
345 * overridden by plugins that need to alter the entry before it is created
346 * at the server.
347 *
348 * @param destinationConnection A connection to the destination server.
349 * @param entryToCreate The entry that will be created at the
350 * destination. A plugin that wishes to
351 * create the entry should be sure to return
352 * {@code PreStepResult#SKIP_CURRENT_STEP}.
353 * @param operation The synchronization operation for this
354 * change.
355 *
356 * @return The result of the plugin processing.
357 *
358 * @throws LDAPException In general subclasses should not catch
359 * LDAPExceptions that are thrown when
360 * using the LDAPInterface unless there
361 * are specific exceptions that are
362 * expected. The Synchronization Server
363 * will handle LDAPExceptions in an
364 * appropriate way based on the specific
365 * cause of the exception. For example,
366 * some errors will result in the
367 * SyncOperation being retried, and others
368 * will trigger fail over to a different
369 * server. Plugins should only throw
370 * LDAPException for errors related to
371 * communication with the LDAP server.
372 * Use the return code to indicate other
373 * types of errors, which might require
374 * retry.
375 */
376 public PreStepResult preCreate(final LDAPInterface destinationConnection,
377 final Entry entryToCreate,
378 final SyncOperation operation)
379 throws LDAPException
380 {
381 return PreStepResult.CONTINUE;
382 }
383
384
385
386 /**
387 * This method is called before a destination entry is modified. A
388 * connection to the destination server is provided along with the
389 * {@code Entry} that will be sent to the server. This method is
390 * overridden by plugins that need to perform some processing on an entry
391 * before it is modified.
392 *
393 * @param destinationConnection A connection to the destination server.
394 * @param entryToModify The entry that will be modified at the
395 * destination. A plugin that wishes to
396 * modify the entry should be sure to return
397 * {@code PreStepResult#SKIP_CURRENT_STEP}.
398 * @param modsToApply A modifiable list of the modifications to
399 * apply at the server.
400 * @param operation The synchronization operation for this
401 * change.
402 *
403 * @return The result of the plugin processing.
404 *
405 * @throws LDAPException In general subclasses should not catch
406 * LDAPExceptions that are thrown when
407 * using the LDAPInterface unless there
408 * are specific exceptions that are
409 * expected. The Synchronization Server
410 * will handle LDAPExceptions in an
411 * appropriate way based on the specific
412 * cause of the exception. For example,
413 * some errors will result in the
414 * SyncOperation being retried, and others
415 * will trigger fail over to a different
416 * server. Plugins should only throw
417 * LDAPException for errors related to
418 * communication with the LDAP server.
419 * Use the return code to indicate other
420 * types of errors, which might require
421 * retry.
422 */
423 public PreStepResult preModify(final LDAPInterface destinationConnection,
424 final Entry entryToModify,
425 final List<Modification> modsToApply,
426 final SyncOperation operation)
427 throws LDAPException
428 {
429 return PreStepResult.CONTINUE;
430 }
431
432
433
434 /**
435 * This method is called before a destination entry is deleted. A
436 * connection to the destination server is provided along with the
437 * {@code Entry} that will be sent to the server. This method is
438 * overridden by plugins that need to perform some processing on an entry
439 * before it is deleted. A plugin could choose to mark an entry as disabled
440 * instead of deleting it for instance, or move the entry to a different
441 * part of the directory hierarchy.
442 *
443 * @param destinationConnection A connection to the destination server.
444 * @param entryToDelete The entry that will be deleted at the
445 * destination. A plugin that wishes to
446 * delete the entry should be sure to return
447 * {@code PreStepResult#SKIP_CURRENT_STEP}.
448 * @param operation The synchronization operation for this
449 * change.
450 *
451 * @return The result of the plugin processing.
452 *
453 * @throws LDAPException In general subclasses should not catch
454 * LDAPExceptions that are thrown when
455 * using the LDAPInterface unless there
456 * are specific exceptions that are
457 * expected. The Synchronization Server
458 * will handle LDAPExceptions in an
459 * appropriate way based on the specific
460 * cause of the exception. For example,
461 * some errors will result in the
462 * SyncOperation being retried, and others
463 * will trigger fail over to a different
464 * server. Plugins should only throw
465 * LDAPException for errors related to
466 * communication with the LDAP server.
467 * Use the return code to indicate other
468 * types of errors, which might require
469 * retry.
470 */
471 public PreStepResult preDelete(final LDAPInterface destinationConnection,
472 final Entry entryToDelete,
473 final SyncOperation operation)
474 throws LDAPException
475 {
476 return PreStepResult.CONTINUE;
477 }
478
479
480
481 /**
482 * Retrieves a string representation of this LDAP sync destination plugin.
483 *
484 * @return A string representation of this LDAP sync destination plugin.
485 */
486 @Override()
487 public final String toString()
488 {
489 final StringBuilder buffer = new StringBuilder();
490 toString(buffer);
491 return buffer.toString();
492 }
493
494
495
496 /**
497 * Appends a string representation of this LDAP sync destination plugin to the
498 * provided buffer.
499 *
500 * @param buffer The buffer to which the string representation should be
501 * appended.
502 */
503 public abstract void toString(final StringBuilder buffer);
504
505
506
507 /**
508 * {@inheritDoc}
509 */
510 public Map<List<String>,String> getExamplesArgumentSets()
511 {
512 return Collections.emptyMap();
513 }
514 }