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 2013-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;
034
035import com.unboundid.directory.sdk.broker.internal.BrokerExtension;
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.types.CompletedOperationContext;
040import com.unboundid.directory.sdk.common.types.CompletedSearchOperationContext;
041import com.unboundid.directory.sdk.ds.config.ResultCriteriaConfig;
042import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
043import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
044import com.unboundid.directory.sdk.metrics.internal.MetricsEngineExtension;
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 can
059 * be used to classify client results.
060 * <BR>
061 * <H2>Configuring Result Criteria</H2>
062 * In order to configure a result criteria object created using this API, use a
063 * command like:
064 * <PRE>
065 *      dsconfig create-result-criteria \
066 *           --criteria-name "<I>{criteria-name}</I>" \
067 *           --type third-party \
068 *           --set enabled:true \
069 *           --set "extension-class:<I>{class-name}</I>" \
070 *           --set "extension-argument:<I>{name=value}</I>"
071 * </PRE>
072 * where "<I>{criteria-name}</I>" is the name to use for the result criteria
073 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java class
074 * that extends {@code com.unboundid.directory.sdk.ds.api.ResultCriteria}, and
075 * "<I>{name=value}</I>" represents name-value pairs for any arguments to
076 * provide to the result criteria.  If multiple arguments should be provided to
077 * the result criteria instance, then the
078 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
079 * provided multiple times.
080 */
081@Extensible()
082@DirectoryServerExtension()
083@DirectoryProxyServerExtension(appliesToLocalContent=true,
084     appliesToRemoteContent=true)
085@SynchronizationServerExtension(appliesToLocalContent=true,
086     appliesToSynchronizedContent=false)
087@MetricsEngineExtension()
088@BrokerExtension()
089@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
090public abstract class ResultCriteria
091       implements UnboundIDExtension,
092                  Reconfigurable<ResultCriteriaConfig>,
093                  ExampleUsageProvider
094{
095  /**
096   * Creates a new instance of this result criteria.  All result criteria
097   * implementations must include a default constructor, but any initialization
098   * should generally be done in the {@code initializeResultCriteria} method.
099   */
100  public ResultCriteria()
101  {
102    // No implementation is required.
103  }
104
105
106
107  /**
108   * {@inheritDoc}
109   */
110  public abstract String getExtensionName();
111
112
113
114  /**
115   * {@inheritDoc}
116   */
117  public abstract String[] getExtensionDescription();
118
119
120
121  /**
122   * {@inheritDoc}
123   */
124  public void defineConfigArguments(final ArgumentParser parser)
125         throws ArgumentException
126  {
127    // No arguments will be allowed by default.
128  }
129
130
131
132  /**
133   * Initializes this result criteria.
134   *
135   * @param  serverContext  A handle to the server context for the server in
136   *                        which this extension is running.
137   * @param  config         The general configuration for this result criteria.
138   * @param  parser         The argument parser which has been initialized from
139   *                        the configuration for this result criteria.
140   *
141   * @throws  LDAPException  If a problem occurs while initializing this result
142   *                         criteria.
143   */
144  public void initializeResultCriteria(
145                   final DirectoryServerContext serverContext,
146                   final ResultCriteriaConfig config,
147                   final ArgumentParser parser)
148         throws LDAPException
149  {
150    // No initialization will be performed by default.
151  }
152
153
154
155  /**
156   * {@inheritDoc}
157   */
158  public boolean isConfigurationAcceptable(
159                      final ResultCriteriaConfig config,
160                      final ArgumentParser parser,
161                      final List<String> unacceptableReasons)
162  {
163    // No extended validation will be performed by default.
164    return true;
165  }
166
167
168
169  /**
170   * {@inheritDoc}
171   */
172  public ResultCode applyConfiguration(final ResultCriteriaConfig config,
173                                       final ArgumentParser parser,
174                                       final List<String> adminActionsRequired,
175                                       final List<String> messages)
176  {
177    // By default, no configuration changes will be applied.  If there are any
178    // arguments, then add an admin action message indicating that the extension
179    // needs to be restarted for any changes to take effect.
180    if (! parser.getNamedArguments().isEmpty())
181    {
182      adminActionsRequired.add(
183           "No configuration change has actually been applied.  The new " +
184                "configuration will not take effect until this result " +
185                "criteria is disabled and re-enabled or until the server is " +
186                "restarted.");
187    }
188
189    return ResultCode.SUCCESS;
190  }
191
192
193
194  /**
195   * Performs any cleanup which may be necessary when this result criteria
196   * is to be taken out of service.
197   */
198  public void finalizeResultCriteria()
199  {
200    // No implementation is required.
201  }
202
203
204
205  /**
206   * Indicates whether the provided operation matches the criteria for this
207   * result criteria object.
208   *
209   * @param  o  The operation for which to make the determination.
210   *
211   * @return  {@code true} if the provided operation matches the criteria for
212   *          this result criteria object, or {@code false} if not.
213   */
214  public abstract boolean matches(final CompletedOperationContext o);
215
216
217
218  /**
219   * Indicates whether the provided search operation matches the criteria for
220   * this result criteria object.  In the default implementation, this method
221   * simply invokes the {@link #matches(CompletedOperationContext)} method, and
222   * therefore it only needs to be overridden if search-specific processing is
223   * needed (e.g., to consider the number of entries or references returned, or
224   * whether the search is unindexed).
225   *
226   * @param  o  The search operation for which to make the determination.
227   *
228   * @return  {@code true} if the provided search operation matches the criteria
229   *          for this result criteria object, or {@code false} if not.
230   */
231  public boolean matches(final CompletedSearchOperationContext o)
232  {
233    return matches((CompletedOperationContext) o);
234  }
235
236
237
238  /**
239   * {@inheritDoc}
240   */
241  public Map<List<String>,String> getExamplesArgumentSets()
242  {
243    return Collections.emptyMap();
244  }
245}