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