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-2021 Ping Identity Corporation
026 */
027package com.unboundid.directory.sdk.ds.api;
028
029
030
031import java.math.BigInteger;
032import java.util.Collections;
033import java.util.List;
034import java.util.Map;
035import java.util.Set;
036
037import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
038import com.unboundid.directory.sdk.common.internal.Reconfigurable;
039import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
040import com.unboundid.directory.sdk.common.operation.AddRequest;
041import com.unboundid.directory.sdk.common.operation.AddResult;
042import com.unboundid.directory.sdk.common.operation.DeleteRequest;
043import com.unboundid.directory.sdk.common.operation.DeleteResult;
044import com.unboundid.directory.sdk.common.operation.ModifyRequest;
045import com.unboundid.directory.sdk.common.operation.ModifyResult;
046import com.unboundid.directory.sdk.common.operation.ModifyDNRequest;
047import com.unboundid.directory.sdk.common.operation.ModifyDNResult;
048import com.unboundid.directory.sdk.common.types.CompletedOperationContext;
049import com.unboundid.directory.sdk.common.types.Entry;
050import com.unboundid.directory.sdk.ds.config.ChangeSubscriptionHandlerConfig;
051import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
052import com.unboundid.directory.sdk.ds.scripting.
053            ScriptedChangeSubscriptionHandler;
054import com.unboundid.directory.sdk.ds.types.ChangeSubscription;
055import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
056import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
057import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
058import com.unboundid.ldap.sdk.LDAPException;
059import com.unboundid.ldap.sdk.ResultCode;
060import com.unboundid.util.Extensible;
061import com.unboundid.util.ThreadSafety;
062import com.unboundid.util.ThreadSafetyLevel;
063import com.unboundid.util.args.ArgumentException;
064import 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)
112public 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}