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.ds.scripting;
028    
029    
030    
031    import java.math.BigInteger;
032    import java.util.List;
033    import java.util.Set;
034    
035    import com.unboundid.directory.sdk.common.internal.Reconfigurable;
036    import com.unboundid.directory.sdk.common.operation.AddRequest;
037    import com.unboundid.directory.sdk.common.operation.AddResult;
038    import com.unboundid.directory.sdk.common.operation.DeleteRequest;
039    import com.unboundid.directory.sdk.common.operation.DeleteResult;
040    import com.unboundid.directory.sdk.common.operation.ModifyRequest;
041    import com.unboundid.directory.sdk.common.operation.ModifyResult;
042    import com.unboundid.directory.sdk.common.operation.ModifyDNRequest;
043    import com.unboundid.directory.sdk.common.operation.ModifyDNResult;
044    import com.unboundid.directory.sdk.common.types.CompletedOperationContext;
045    import com.unboundid.directory.sdk.common.types.Entry;
046    import com.unboundid.directory.sdk.ds.config.ChangeSubscriptionHandlerConfig;
047    import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
048    import com.unboundid.directory.sdk.ds.types.ChangeSubscription;
049    import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
050    import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
051    import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
052    import com.unboundid.ldap.sdk.LDAPException;
053    import com.unboundid.ldap.sdk.ResultCode;
054    import com.unboundid.util.Extensible;
055    import com.unboundid.util.ThreadSafety;
056    import com.unboundid.util.ThreadSafetyLevel;
057    import com.unboundid.util.args.ArgumentException;
058    import com.unboundid.util.args.ArgumentParser;
059    
060    
061    
062    /**
063     * This class defines an API that must be implemented by scripted extensions
064     * which receive notification of changes of interest processed within the
065     * server.  The server may be configured with one or more change subscriptions,
066     * which use criteria to identify the types of changes that should be made
067     * available to change subscription handlers.  Each change subscription handler
068     * may be configured either to be notified only for changes matching a specific
069     * set of change subscriptions, or for changes matching the criteria for any
070     * subscription defined in the server.  This is handled automatically by the
071     * server, so individual change subscription handler implementations do not need
072     * to attempt to perform that filtering on their own.  However, they may perform
073     * additional processing if desired to further narrow the set of changes to be
074     * processed.
075     * <BR>
076     * <H2>Configuring Groovy-Scripted Change Subscription Handlers</H2>
077     * In order to configure a scripted change subscription handler based on this
078     * API and written in the Groovy scripting language, use a command like:
079     * <PRE>
080     *      dsconfig create-change-subscription-handler \
081     *           --handler-name "<I>{handler-name}</I>" \
082     *           --type groovy-scripted \
083     *           --set enabled:true \
084     *           --set "script-class:<I>{class-name}</I>" \
085     *           --set "script-argument:<I>{name=value}</I>"
086     * </PRE>
087     * where "<I>{handler-name}</I>" is the name to use for the change subscription
088     * handler instance, "<I>{class-name}</I>" is the fully-qualified name of the
089     * Groovy class written using this API, and "<I>{name=value}</I>" represents
090     * name-value pairs for any arguments to provide to the change subscription
091     * handler.  If multiple arguments should be provided to the change subscription
092     * handler, then the "<CODE>--set script-argument:<I>{name=value}</I></CODE>"
093     * option should be provided multiple times.
094     *
095     * @see  com.unboundid.directory.sdk.ds.api.ChangeSubscriptionHandler
096     */
097    @Extensible()
098    @DirectoryServerExtension()
099    @DirectoryProxyServerExtension(appliesToLocalContent=true,
100         appliesToRemoteContent=false)
101    @SynchronizationServerExtension(appliesToLocalContent=true,
102         appliesToSynchronizedContent=false)
103    @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
104    public abstract class ScriptedChangeSubscriptionHandler
105           implements Reconfigurable<ChangeSubscriptionHandlerConfig>
106    {
107      /**
108       * Creates a new instance of this change subscription handler.  All change
109       * subscription handler implementations must include a default constructor,
110       * but any initialization should generally be done in the
111       * {@code initializeChangeSubscriptionHandler} method.
112       */
113      public ScriptedChangeSubscriptionHandler()
114      {
115        // No implementation is required.
116      }
117    
118    
119    
120      /**
121       * {@inheritDoc}
122       */
123      public void defineConfigArguments(final ArgumentParser parser)
124             throws ArgumentException
125      {
126        // No arguments will be allowed by default.
127      }
128    
129    
130    
131      /**
132       * Initializes this change subscription handler.
133       *
134       * @param  serverContext  A handle to the server context for the server in
135       *                        which this extension is running.
136       * @param  config         The general configuration for this change
137       *                        subscription handler.
138       * @param  parser         The argument parser which has been initialized from
139       *                        the configuration for this change subscription
140       *                        handler.
141       *
142       * @throws  LDAPException  If a problem occurs while initializing this change
143       *                         subscription handler.
144       */
145      public void initializeChangeSubscriptionHandler(
146                       final DirectoryServerContext serverContext,
147                       final ChangeSubscriptionHandlerConfig config,
148                       final ArgumentParser parser)
149             throws LDAPException
150      {
151        // No initialization will be performed by default.
152      }
153    
154    
155    
156      /**
157       * Performs any cleanup which may be necessary when this change subscription
158       * handler is to be taken out of service.
159       */
160      public void finalizeChangeSubscriptionHandler()
161      {
162        // No implementation is required.
163      }
164    
165    
166    
167      /**
168       * {@inheritDoc}
169       */
170      public boolean isConfigurationAcceptable(
171                          final ChangeSubscriptionHandlerConfig config,
172                          final ArgumentParser parser,
173                          final List<String> unacceptableReasons)
174      {
175        // No extended validation will be performed.
176        return true;
177      }
178    
179    
180    
181      /**
182       * {@inheritDoc}
183       */
184      public ResultCode applyConfiguration(
185                             final ChangeSubscriptionHandlerConfig config,
186                             final ArgumentParser parser,
187                             final List<String> adminActionsRequired,
188                             final List<String> messages)
189      {
190        // By default, no configuration changes will be applied.  If there are any
191        // arguments, then add an admin action message indicating that the extension
192        // needs to be restarted for any changes to take effect.
193        if (! parser.getNamedArguments().isEmpty())
194        {
195          adminActionsRequired.add(
196               "No configuration change has actually been applied.  The new " +
197                    "configuration will not take effect until this change " +
198                    "subscription handler is disabled and re-enabled or until " +
199                    "the server is restarted.");
200        }
201    
202        return ResultCode.SUCCESS;
203      }
204    
205    
206    
207      /**
208       * Performs any processing necessary for an add operation matching the
209       * subscription criteria.
210       *
211       * @param  operationContext     The context for the add operation.
212       * @param  sequenceNumber       The sequence number for the change
213       *                              subscription notification.
214       * @param  changeSubscriptions  The set of change subscriptions whose criteria
215       *                              matched the add operation.
216       * @param  addRequest           Information about the request for the add
217       *                              operation that was processed.
218       * @param  addResult            Information about the result for the add
219       *                              operation that was processed.
220       * @param  entry                The entry that was added to the server.
221       */
222      public abstract void addOperationProcessed(
223                                final CompletedOperationContext operationContext,
224                                final BigInteger sequenceNumber,
225                                final Set<ChangeSubscription> changeSubscriptions,
226                                final AddRequest addRequest,
227                                final AddResult addResult, final Entry entry);
228    
229    
230    
231      /**
232       * Performs any processing necessary for a delete operation matching the
233       * subscription criteria.
234       *
235       * @param  operationContext     The context for the delete operation.
236       * @param  sequenceNumber       The sequence number for the change
237       *                              subscription notification.
238       * @param  changeSubscriptions  The set of change subscriptions whose criteria
239       *                              matched the delete operation.
240       * @param  deleteRequest        Information about the request for the delete
241       *                              operation that was processed.
242       * @param  deleteResult         Information about the result for the delete
243       *                              operation that was processed.
244       * @param  entry                The entry that was removed from the server.
245       */
246      public abstract void deleteOperationProcessed(
247                                final CompletedOperationContext operationContext,
248                                final BigInteger sequenceNumber,
249                                final Set<ChangeSubscription> changeSubscriptions,
250                                final DeleteRequest deleteRequest,
251                                final DeleteResult deleteResult,
252                                final Entry entry);
253    
254    
255    
256      /**
257       * Performs any processing necessary for a modify operation matching the
258       * subscription criteria.
259       *
260       * @param  operationContext     The context for the modify operation.
261       * @param  sequenceNumber       The sequence number for the change
262       *                              subscription notification.
263       * @param  changeSubscriptions  The set of change subscriptions whose criteria
264       *                              matched the modify operation.
265       * @param  modifyRequest        Information about the request for the modify
266       *                              operation that was processed.
267       * @param  modifyResult         Information about the result for the modify
268       *                              operation that was processed.
269       * @param  oldEntry             The entry as it appeared before the changes
270       *                              were applied.
271       * @param  newEntry             The entry as it appeared immediately after the
272       *                              changes were applied.
273       */
274      public abstract void modifyOperationProcessed(
275                                final CompletedOperationContext operationContext,
276                                final BigInteger sequenceNumber,
277                                final Set<ChangeSubscription> changeSubscriptions,
278                                final ModifyRequest modifyRequest,
279                                final ModifyResult modifyResult,
280                                final Entry oldEntry, final Entry newEntry);
281    
282    
283    
284      /**
285       * Performs any processing necessary for a modify DN operation matching the
286       * subscription criteria.
287       *
288       * @param  operationContext     The context for the modify DN operation.
289       * @param  sequenceNumber       The sequence number for the change
290       *                              subscription notification.
291       * @param  changeSubscriptions  The set of change subscriptions whose criteria
292       *                              matched the modify DN operation.
293       * @param  modifyDNRequest      Information about the request for the modify
294       *                              DN operation that was processed.
295       * @param  modifyDNResult       Information about the result for the modify DN
296       *                              operation that was processed.
297       * @param  oldEntry             The entry as it appeared before being renamed.
298       * @param  newEntry             The entry as it appeared immediately after
299       *                              being renamed.
300       */
301      public abstract void modifyDNOperationProcessed(
302                                final CompletedOperationContext operationContext,
303                                final BigInteger sequenceNumber,
304                                final Set<ChangeSubscription> changeSubscriptions,
305                                final ModifyDNRequest modifyDNRequest,
306                                final ModifyDNResult modifyDNResult,
307                                final Entry oldEntry, final Entry newEntry);
308    }