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