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.api;
028
029
030
031import java.util.Collections;
032import java.util.List;
033import java.util.Map;
034import java.util.Set;
035
036import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
037import com.unboundid.directory.sdk.common.internal.Reconfigurable;
038import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
039import com.unboundid.directory.sdk.common.operation.ExtendedRequest;
040import com.unboundid.directory.sdk.common.operation.UpdatableExtendedResult;
041import com.unboundid.directory.sdk.common.types.OperationContext;
042import com.unboundid.directory.sdk.ds.config.ExtendedOperationHandlerConfig;
043import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
044import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
045import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
046import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
047import com.unboundid.ldap.sdk.LDAPException;
048import com.unboundid.ldap.sdk.ResultCode;
049import com.unboundid.util.Extensible;
050import com.unboundid.util.ThreadSafety;
051import com.unboundid.util.ThreadSafetyLevel;
052import com.unboundid.util.args.ArgumentException;
053import com.unboundid.util.args.ArgumentParser;
054
055
056
057/**
058 * This class defines an API that must be implemented by extensions which are
059 * used to process extended operations within the server.  Extended operations
060 * may be used to perform processing which falls outside of that available by
061 * the core set of LDAP operations.  Each extended request will include a
062 * numeric object identifier (OID) which indicates the type of request to be
063 * processed, and may also include a value with additional information about the
064 * processing to be performed.  Each extended operation handler must specify the
065 * OIDs of the types of extended requests that it may be used to process.
066 * <BR>
067 * <H2>Configuring Extended Operation Handlers</H2>
068 * In order to configure an extended operation handler created using this API,
069 * use a command like:
070 * <PRE>
071 *      dsconfig create-extended-operation-handler \
072 *           --handler-name "<I>{handler-name}</I>" \
073 *           --type third-party \
074 *           --set enabled:true \
075 *           --set "extension-class:<I>{class-name}</I>" \
076 *           --set "extension-argument:<I>{name=value}</I>"
077 * </PRE>
078 * where "<I>{handler-name}</I>" is the name to use for the extended operation
079 * handler instance, "<I>{class-name}</I>" is the fully-qualified name of the
080 * Java class that extends
081 * {@code com.unboundid.directory.sdk.ds.api.ExtendedOperationHandler}, and
082 * "<I>{name=value}</I>" represents name-value pairs for any arguments to
083 * provide to the extended operation handler.  If multiple arguments should be
084 * provided to the extended operation handler, then the
085 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
086 * provided multiple times.
087 */
088@Extensible()
089@DirectoryServerExtension()
090@DirectoryProxyServerExtension(appliesToLocalContent=true,
091     appliesToRemoteContent=true,
092     notes="Some extended operation handlers may only apply to local content")
093@SynchronizationServerExtension(appliesToLocalContent=true,
094     appliesToSynchronizedContent=false)
095@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
096public abstract class ExtendedOperationHandler
097       implements UnboundIDExtension,
098                  Reconfigurable<ExtendedOperationHandlerConfig>,
099                  ExampleUsageProvider
100{
101  /**
102   * Creates a new instance of this extended operation handler.  All extended
103   * operation handler implementations must include a default constructor, but
104   * any initialization should generally be done in the
105   * {@code initializeExtendedOperationHandler} method.
106   */
107  public ExtendedOperationHandler()
108  {
109    // No implementation is required.
110  }
111
112
113
114  /**
115   * {@inheritDoc}
116   */
117  public abstract String getExtensionName();
118
119
120
121  /**
122   * {@inheritDoc}
123   */
124  public abstract String[] getExtensionDescription();
125
126
127
128  /**
129   * {@inheritDoc}
130   */
131  public void defineConfigArguments(final ArgumentParser parser)
132         throws ArgumentException
133  {
134    // No arguments will be allowed by default.
135  }
136
137
138
139  /**
140   * Initializes this extended operation handler.
141   *
142   * @param  serverContext  A handle to the server context for the server in
143   *                        which this extension is running.
144   * @param  config         The general configuration for this extended
145   *                        operation handler.
146   * @param  parser         The argument parser which has been initialized from
147   *                        the configuration for this extended operation
148   *                        handler.
149   *
150   * @throws  LDAPException  If a problem occurs while initializing this
151   *                         extended operation handler.
152   */
153  public void initializeExtendedOperationHandler(
154                   final DirectoryServerContext serverContext,
155                   final ExtendedOperationHandlerConfig config,
156                   final ArgumentParser parser)
157         throws LDAPException
158  {
159    // No initialization will be performed by default.
160  }
161
162
163
164  /**
165   * {@inheritDoc}
166   */
167  public boolean isConfigurationAcceptable(
168                      final ExtendedOperationHandlerConfig config,
169                      final ArgumentParser parser,
170                      final List<String> unacceptableReasons)
171  {
172    // No extended validation will be performed by default.
173    return true;
174  }
175
176
177
178  /**
179   * {@inheritDoc}
180   */
181  public ResultCode applyConfiguration(
182                         final ExtendedOperationHandlerConfig config,
183                         final ArgumentParser parser,
184                         final List<String> adminActionsRequired,
185                         final List<String> messages)
186  {
187    // By default, no configuration changes will be applied.  If there are any
188    // arguments, then add an admin action message indicating that the extension
189    // needs to be restarted for any changes to take effect.
190    if (! parser.getNamedArguments().isEmpty())
191    {
192      adminActionsRequired.add(
193           "No configuration change has actually been applied.  The new " +
194                "configuration will not take effect until this extended " +
195                "operation handler is disabled and re-enabled or until the " +
196                "server is restarted.");
197    }
198
199    return ResultCode.SUCCESS;
200  }
201
202
203
204  /**
205   * Performs any cleanup which may be necessary when this extended operation
206   * handler is to be taken out of service.
207   */
208  public void finalizeExtendedOperationHandler()
209  {
210    // No implementation is required.
211  }
212
213
214
215  /**
216   * Retrieves the name of the extended operation with the provided OID.
217   *
218   * @param  oid  The OID of the extended operation for which to retrieve the
219   *              corresponding name.
220   *
221   * @return  The name of the extended operation with the specified OID, or
222   *          {@code null} if the specified OID is not recognized by this
223   *          extended operation handler.
224   */
225  public abstract String getExtendedOperationName(final String oid);
226
227
228
229  /**
230   * Retrieves the OIDs of the extended operation types supported by this
231   * extended operation handler.
232   *
233   * @return  The OIDs of the extended operation types supported by this
234   *          extended operation handler.  It must not be {@code null} or
235   *          empty, and the contents of the set returned must not change over
236   *          the life of this extended operation handler.
237   */
238  public abstract Set<String> getSupportedExtensions();
239
240
241
242  /**
243   * Retrieves the OIDs of any controls supported by this extended operation
244   * handler.
245   *
246   * @return  The OIDs of any controls supported by this extended operation
247   *          handler.  It may be {@code null} or empty if this extended
248   *          operation handler does not support any controls.
249   */
250  public Set<String> getSupportedControls()
251  {
252    return Collections.emptySet();
253  }
254
255
256
257  /**
258   * Retrieves the OIDs of any features supported by this extended operation
259   * handler that should be advertised in the server root DSE.
260   *
261   * @return  The OIDs of any features supported by this extended operation
262   *          handler.  It may be {@code null} or empty if this extended
263   *          operation handler does not support any features.
264   */
265  public Set<String> getSupportedFeatures()
266  {
267    return Collections.emptySet();
268  }
269
270
271
272  /**
273   * Performs any processing appropriate for the provided extended request.
274   *
275   * @param  operationContext  The operation context for the extended operation.
276   * @param  request           The extended request to be processed.
277   * @param  result            The extended result to be updated with the result
278   *                           of processing.
279   */
280  public abstract void processExtendedOperation(
281                            final OperationContext operationContext,
282                            final ExtendedRequest request,
283                            final UpdatableExtendedResult result);
284
285
286
287  /**
288   * {@inheritDoc}
289   */
290  public Map<List<String>,String> getExamplesArgumentSets()
291  {
292    return Collections.emptyMap();
293  }
294}