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.proxy.api; 028 029 030 031 import java.util.Collections; 032 import java.util.List; 033 import java.util.Map; 034 035 import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider; 036 import com.unboundid.directory.sdk.common.internal.Reconfigurable; 037 import com.unboundid.directory.sdk.common.internal.UnboundIDExtension; 038 import com.unboundid.directory.sdk.common.operation.AddRequest; 039 import com.unboundid.directory.sdk.common.types.OperationContext; 040 import com.unboundid.directory.sdk.proxy.config.PlacementAlgorithmConfig; 041 import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension; 042 import com.unboundid.directory.sdk.proxy.types.BackendSet; 043 import com.unboundid.directory.sdk.proxy.types.ProxyServerContext; 044 import com.unboundid.ldap.sdk.LDAPException; 045 import com.unboundid.ldap.sdk.ResultCode; 046 import com.unboundid.util.Extensible; 047 import com.unboundid.util.ThreadSafety; 048 import com.unboundid.util.ThreadSafetyLevel; 049 import com.unboundid.util.args.ArgumentException; 050 import com.unboundid.util.args.ArgumentParser; 051 052 053 054 /** 055 * This class defines an API that must be implemented by extensions which are 056 * used to select the backend set in which a new entry should be added in an 057 * entry-balanced environment. The decision may be based on a wide range of 058 * factors, including the contents of the entry to be added, the number of 059 * entries in each of the backend servers, or other kinds of criteria. 060 * <BR><BR> 061 * Note that the placement algorithm will only be used for entries which are 062 * immediate subordinates of the entry which is the balancing point. Entries 063 * which are more than one level below the balancing point will automatically 064 * be added into the same backend set as their parent entry. 065 * <BR> 066 * <H2>Configuring Placement Algorithms</H2> 067 * In order to configure a placement algorithm created using this API, use a 068 * command like: 069 * <PRE> 070 * dsconfig create-placement-algorithm \ 071 * --algorithm-name "<I>{algorithm-name}</I>" \ 072 * --processor-name "<I>{processor-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>{algorithm-name}</I>" is the to use for the placement algorithm 079 * instance, "<I>{processor-name}</I>" is the name of the entry-balancing 080 * request processor for which the placement algorithm will be used, 081 * "<I>{class-name}</I>" is the fully-qualified name of the Java class 082 * that extends 083 * {@code com.unboundid.directory.sdk.proxy.api.PlacementAlgorithm}, and 084 * "<I>{name=value}</I>" represents name-value pairs for any arguments to 085 * provide to the placement algorithm. If multiple arguments should be provided 086 * to the placement algorithm, then the 087 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be 088 * provided multiple times. 089 */ 090 @Extensible() 091 @DirectoryProxyServerExtension(appliesToLocalContent=false, 092 appliesToRemoteContent=true) 093 @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE) 094 public abstract class PlacementAlgorithm 095 implements UnboundIDExtension, Reconfigurable<PlacementAlgorithmConfig>, 096 ExampleUsageProvider 097 { 098 /** 099 * Creates a new instance of this placement algorithm. All placement 100 * algorithm implementations must include a default constructor, but any 101 * initialization should generally be done in the 102 * {@code initializePlacementAlgorithm} method. 103 */ 104 public PlacementAlgorithm() 105 { 106 // No implementation is required. 107 } 108 109 110 111 /** 112 * {@inheritDoc} 113 */ 114 public abstract String getExtensionName(); 115 116 117 118 /** 119 * {@inheritDoc} 120 */ 121 public abstract String[] getExtensionDescription(); 122 123 124 125 /** 126 * {@inheritDoc} 127 */ 128 public void defineConfigArguments(final ArgumentParser parser) 129 throws ArgumentException 130 { 131 // No arguments will be allowed by default. 132 } 133 134 135 136 /** 137 * Initializes this placement algorithm. 138 * 139 * @param serverContext A handle to the server context for the Directory 140 * Proxy server in which this extension is running. 141 * @param config The general configuration for this placement 142 * algorithm. 143 * @param parser The argument parser which has been initialized 144 * from the configuration for this placement 145 * algorithm.. 146 * @param balancingBaseDN The balancing base DN for the associated 147 * entry-balancing request processor. 148 * @param backendSets The list of backend sets that will be used with 149 * the entry-balancing request processor. 150 * 151 * @throws LDAPException If a problem occurs while initializing this LDAP 152 * health check. 153 */ 154 public void initializePlacementAlgorithm( 155 final ProxyServerContext serverContext, 156 final PlacementAlgorithmConfig config, 157 final ArgumentParser parser, 158 final String balancingBaseDN, 159 final List<BackendSet> backendSets) 160 throws LDAPException 161 { 162 // No initialization will be performed by default. 163 } 164 165 166 167 /** 168 * {@inheritDoc} 169 */ 170 public boolean isConfigurationAcceptable( 171 final PlacementAlgorithmConfig config, 172 final ArgumentParser parser, 173 final List<String> unacceptableReasons) 174 { 175 // No extended validation will be performed by default. 176 return true; 177 } 178 179 180 181 /** 182 * {@inheritDoc} 183 */ 184 public ResultCode applyConfiguration(final PlacementAlgorithmConfig config, 185 final ArgumentParser parser, 186 final List<String> adminActionsRequired, 187 final List<String> messages) 188 { 189 // By default, no configuration changes will be applied. If there are any 190 // arguments, then add an admin action message indicating that the extension 191 // needs to be restarted for any changes to take effect. 192 if (! parser.getNamedArguments().isEmpty()) 193 { 194 adminActionsRequired.add( 195 "No configuration change has actually been applied. The new " + 196 "configuration will not take effect until this placement " + 197 "algorithm is disabled and re-enabled or until the server " + 198 "is restarted."); 199 } 200 201 return ResultCode.SUCCESS; 202 } 203 204 205 206 /** 207 * Performs any cleanup which may be necessary when this LDAP health check is 208 * to be taken out of service. 209 */ 210 public void finalizePlacementAlgorithm() 211 { 212 // No implementation is required. 213 } 214 215 216 217 /** 218 * Adapts to a change in the backend sets configured for use with the 219 * associated entry-balancing request processor. 220 * 221 * @param balancingBaseDN The updated balancing base DN for the associated 222 * entry-balancing request processor. 223 * @param backendSets The updated list of backend sets for the 224 * associated entry-balancing request processor. 225 */ 226 public abstract void applyBalancingConfigurationChange( 227 final String balancingBaseDN, 228 final List<BackendSet> backendSets); 229 230 231 232 /** 233 * Determines the backend set that should be used to process the specified 234 * add operation. 235 * 236 * @param operationContext The operation context for the add operation 237 * to be processed. 238 * @param addRequest The add request being processed. 239 * 240 * @return The backend set in which the add should be processed, or 241 * {@code null} if there is no appropriate backend set. 242 */ 243 public abstract BackendSet selectBackendSet( 244 final OperationContext operationContext, 245 final AddRequest addRequest); 246 247 248 249 /** 250 * Select a new backend set for an entry that has been modified or a child 251 * entry that has been added below an existing entry in a backend set. 252 * 253 * @param operationContext The operation context for the operation that was 254 * processed. 255 * @param backendSet The backend set that currently holds the entry. 256 * 257 * @return The backend set where the modified or added entry should be 258 * relocated, or {@code null} if the entry should not be relocated. 259 */ 260 public BackendSet selectRebalancingBackendSet( 261 final OperationContext operationContext, 262 final BackendSet backendSet) 263 { 264 // The default implementation is not do any rebalancing. 265 return null; 266 } 267 268 269 270 /** 271 * Determines whether this placement algorithm implements the 272 * {@link #selectRebalancingBackendSet} method to rebalance existing entries. 273 * 274 * @return {@code true} if this placement algorithm supports re-balancing, 275 * or {@code false} if not. 276 */ 277 public boolean supportsRebalancing() 278 { 279 // The default implementation is that re-balancing is not supported. 280 return false; 281 } 282 283 284 285 /** 286 * Retrieves a string representation of this placement algorithm. 287 * 288 * @return A string representation of this placement algorithm. 289 */ 290 @Override() 291 public final String toString() 292 { 293 final StringBuilder buffer = new StringBuilder(); 294 toString(buffer); 295 return buffer.toString(); 296 } 297 298 299 300 /** 301 * Appends a string representation of this placement algorithm to the provided 302 * buffer. 303 * 304 * @param buffer The buffer to which the string representation should be 305 * appended. 306 */ 307 public abstract void toString(final StringBuilder buffer); 308 309 310 311 /** 312 * {@inheritDoc} 313 */ 314 public Map<List<String>,String> getExamplesArgumentSets() 315 { 316 return Collections.emptyMap(); 317 } 318 }