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