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-2013 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    }