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-2012 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 * Retrieves a string representation of this placement algorithm.
251 *
252 * @return A string representation of this placement algorithm.
253 */
254 @Override()
255 public final String toString()
256 {
257 final StringBuilder buffer = new StringBuilder();
258 toString(buffer);
259 return buffer.toString();
260 }
261
262
263
264 /**
265 * Appends a string representation of this placement algorithm to the provided
266 * buffer.
267 *
268 * @param buffer The buffer to which the string representation should be
269 * appended.
270 */
271 public abstract void toString(final StringBuilder buffer);
272
273
274
275 /**
276 * {@inheritDoc}
277 */
278 public Map<List<String>,String> getExamplesArgumentSets()
279 {
280 return Collections.emptyMap();
281 }
282 }