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.scripting;
028
029
030
031 import java.util.List;
032 import java.util.concurrent.atomic.AtomicReference;
033
034 import com.unboundid.directory.sdk.common.internal.Reconfigurable;
035 import com.unboundid.directory.sdk.sync.config.LDAPSyncSourcePluginConfig;
036 import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
037 import com.unboundid.directory.sdk.sync.types.PostStepResult;
038 import com.unboundid.directory.sdk.sync.types.SyncOperation;
039 import com.unboundid.directory.sdk.sync.types.SyncServerContext;
040 import com.unboundid.ldap.sdk.Entry;
041 import com.unboundid.ldap.sdk.LDAPException;
042 import com.unboundid.ldap.sdk.LDAPInterface;
043 import com.unboundid.ldap.sdk.ResultCode;
044 import com.unboundid.util.Extensible;
045 import com.unboundid.util.ThreadSafety;
046 import com.unboundid.util.ThreadSafetyLevel;
047 import com.unboundid.util.args.ArgumentException;
048 import 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 Synchronization 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)
094 public 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 Synchronization 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 }