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