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