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