001/*
002 * Copyright 2008-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2018 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk.unboundidds.tasks;
022
023
024
025import java.util.ArrayList;
026import java.util.Arrays;
027import java.util.Collections;
028import java.util.Date;
029import java.util.LinkedHashMap;
030import java.util.List;
031import java.util.Map;
032
033import com.unboundid.ldap.sdk.Attribute;
034import com.unboundid.ldap.sdk.Entry;
035import com.unboundid.util.NotMutable;
036import com.unboundid.util.ThreadSafety;
037import com.unboundid.util.ThreadSafetyLevel;
038
039import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*;
040import static com.unboundid.util.Debug.*;
041import static com.unboundid.util.Validator.*;
042
043
044
045/**
046 * This class defines a Directory Server task that can be used to generate
047 * and/or rebuild one or more indexes a Berkeley DB Java Edition backend.
048 * <BR>
049 * <BLOCKQUOTE>
050 *   <B>NOTE:</B>  This class, and other classes within the
051 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
052 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
053 *   server products.  These classes provide support for proprietary
054 *   functionality or for external specifications that are not considered stable
055 *   or mature enough to be guaranteed to work in an interoperable way with
056 *   other types of LDAP servers.
057 * </BLOCKQUOTE>
058 * <BR>
059 * The properties that are available for use with this type of task include:
060 * <UL>
061 *   <LI>The backend base DN for which to perform the index rebuild.  This
062 *       must be provided when scheduling a rebuild task.</LI>
063 *   <LI>The names of the indexes to be built.  At least one index name must be
064 *       provided when scheduling a rebuild task.</LI>
065 *   <LI>The maximum number of concurrent threads that should be used to perform
066 *       the processing.  A value of zero indicates that there is no limit.</LI>
067 * </UL>
068
069 */
070@NotMutable()
071@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
072public final class RebuildTask
073       extends Task
074{
075  /**
076   * The fully-qualified name of the Java class that is used for the rebuild
077   * task.
078   */
079  static final String REBUILD_TASK_CLASS =
080       "com.unboundid.directory.server.tasks.RebuildTask";
081
082
083
084  /**
085   * The name of the attribute used to specify the base DN for which to rebuild
086   * the specified indexes.
087   */
088  private static final String ATTR_BASE_DN = "ds-task-rebuild-base-dn";
089
090
091
092  /**
093   * The name of the attribute used to specify the names of the indexes to
094   * rebuild.
095   */
096  private static final String ATTR_INDEX = "ds-task-rebuild-index";
097
098
099
100  /**
101   * The name of the attribute used to specify the maximum number of concurrent
102   * threads to use to perform the rebuild.
103   */
104  private static final String ATTR_MAX_THREADS = "ds-task-rebuild-max-threads";
105
106
107
108  /**
109   * The name of the object class used in rebuild task entries.
110   */
111  private static final String OC_REBUILD_TASK = "ds-task-rebuild";
112
113
114
115  /**
116   * The task property for the base DN.
117   */
118  private static final TaskProperty PROPERTY_BASE_DN =
119       new TaskProperty(ATTR_BASE_DN, INFO_DISPLAY_NAME_BASE_DN_REBUILD.get(),
120                        INFO_DESCRIPTION_BASE_DN_REBUILD.get(), String.class,
121                        true, false, false);
122
123
124
125  /**
126   * The task property for the index names.
127   */
128  private static final TaskProperty PROPERTY_INDEX =
129       new TaskProperty(ATTR_INDEX, INFO_DISPLAY_NAME_INDEX_REBUILD.get(),
130                        INFO_DESCRIPTION_INDEX_REBUILD.get(), String.class,
131                        true, true, false);
132
133
134
135  /**
136   * The task property for the max threads value.
137   */
138  private static final TaskProperty PROPERTY_MAX_THREADS =
139       new TaskProperty(ATTR_MAX_THREADS,
140                        INFO_DISPLAY_NAME_MAX_THREADS_REBUILD.get(),
141                        INFO_DESCRIPTION_MAX_THREADS_REBUILD.get(), Long.class,
142                        false, false, true);
143
144
145
146  /**
147   * The serial version UID for this serializable class.
148   */
149  private static final long serialVersionUID = 6015907901926792443L;
150
151
152
153  // The maximum number of threads to use to rebuild indexes.
154  private final int maxThreads;
155
156  // The base DN for which to rebuild indexes.
157  private final String baseDN;
158
159  // The names of the indexes to rebuild.
160  private final List<String> indexes;
161
162
163
164  /**
165   * Creates a new uninitialized rebuild task instance which should only be used
166   * for obtaining general information about this task, including the task name,
167   * description, and supported properties.  Attempts to use a task created with
168   * this constructor for any other reason will likely fail.
169   */
170  public RebuildTask()
171  {
172    baseDN     = null;
173    maxThreads = -1;
174    indexes    = null;
175  }
176
177
178
179  /**
180   * Creates a new rebuild task with the provided information.
181   *
182   * @param  taskID   The task ID to use for this task.  If it is {@code null}
183   *                  then a UUID will be generated for use as the task ID.
184   * @param  baseDN   The base DN for which to rebuild the index.  It must refer
185   *                  to a base DN for a Berkeley DB Java Edition backend.  It
186   *                  must not be {@code null}.
187   * @param  indexes  A list containing the names of the indexes to rebuild.  It
188   *                  must not be {@code null} or empty.
189   */
190  public RebuildTask(final String taskID, final String baseDN,
191                     final List<String> indexes)
192  {
193    this(taskID, baseDN, indexes, -1, null, null, null, null, null);
194  }
195
196
197
198  /**
199   * Creates a new rebuild task with the provided information.
200   *
201   * @param  taskID                  The task ID to use for this task.  If it is
202   *                                 {@code null} then a UUID will be generated
203   *                                 for use as the task ID.
204   * @param  baseDN                  The base DN for which to rebuild the index.
205   *                                 It must refer to a base DN for a Berkeley
206   *                                 DB Java Edition backend.  It must not be
207   *                                 {@code null}.
208   * @param  indexes                 A list containing the names of the indexes
209   *                                 to rebuild.  It must not be {@code null} or
210   *                                 empty.
211   * @param  maxThreads              The maximum number of concurrent threads to
212   *                                 use while performing the rebuild.  A value
213   *                                 less than or equal to zero indicates that
214   *                                 there is no limit to the number of threads
215   *                                 that may be used.
216   * @param  scheduledStartTime      The time that this task should start
217   *                                 running.
218   * @param  dependencyIDs           The list of task IDs that will be required
219   *                                 to complete before this task will be
220   *                                 eligible to start.
221   * @param  failedDependencyAction  Indicates what action should be taken if
222   *                                 any of the dependencies for this task do
223   *                                 not complete successfully.
224   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
225   *                                 that should be notified when this task
226   *                                 completes.
227   * @param  notifyOnError           The list of e-mail addresses of individuals
228   *                                 that should be notified if this task does
229   *                                 not complete successfully.
230   */
231  public RebuildTask(final String taskID, final String baseDN,
232                     final List<String> indexes, final int maxThreads,
233                     final Date scheduledStartTime,
234                     final List<String> dependencyIDs,
235                     final FailedDependencyAction failedDependencyAction,
236                     final List<String> notifyOnCompletion,
237                     final List<String> notifyOnError)
238  {
239    super(taskID, REBUILD_TASK_CLASS, scheduledStartTime, dependencyIDs,
240          failedDependencyAction, notifyOnCompletion, notifyOnError);
241
242    ensureNotNull(baseDN, indexes);
243    ensureFalse(indexes.isEmpty(),
244                "RebuildTask.indexes must not be empty.");
245
246    this.baseDN     = baseDN;
247    this.indexes    = Collections.unmodifiableList(indexes);
248    this.maxThreads = maxThreads;
249  }
250
251
252
253  /**
254   * Creates a new rebuild task from the provided entry.
255   *
256   * @param  entry  The entry to use to create this rebuild task.
257   *
258   * @throws  TaskException  If the provided entry cannot be parsed as a rebuild
259   *                         task entry.
260   */
261  public RebuildTask(final Entry entry)
262         throws TaskException
263  {
264    super(entry);
265
266
267    // Get the base DN.  It must be present.
268    baseDN = entry.getAttributeValue(ATTR_BASE_DN);
269    if (baseDN == null)
270    {
271      throw new TaskException(ERR_REBUILD_TASK_NO_BASE_DN.get(
272                                   getTaskEntryDN()));
273    }
274
275
276    // Get the names of the indexes to rebuild.  It must be present.
277    final String[] indexArray = entry.getAttributeValues(ATTR_INDEX);
278    if ((indexArray == null) || (indexArray.length == 0))
279    {
280      throw new TaskException(ERR_REBUILD_TASK_NO_INDEXES.get(
281                                   getTaskEntryDN()));
282    }
283    else
284    {
285      indexes = Collections.unmodifiableList(Arrays.asList(indexArray));
286    }
287
288
289    // Get the maximum number of threads to use.
290    final String threadsStr = entry.getAttributeValue(ATTR_MAX_THREADS);
291    if (threadsStr == null)
292    {
293      maxThreads = -1;
294    }
295    else
296    {
297      try
298      {
299        maxThreads = Integer.parseInt(threadsStr);
300      }
301      catch (final Exception e)
302      {
303        debugException(e);
304        throw new TaskException(ERR_REBUILD_TASK_INVALID_MAX_THREADS.get(
305                                     getTaskEntryDN(), threadsStr), e);
306      }
307    }
308  }
309
310
311
312  /**
313   * Creates a new rebuild task from the provided set of task properties.
314   *
315   * @param  properties  The set of task properties and their corresponding
316   *                     values to use for the task.  It must not be
317   *                     {@code null}.
318   *
319   * @throws  TaskException  If the provided set of properties cannot be used to
320   *                         create a valid rebuild task.
321   */
322  public RebuildTask(final Map<TaskProperty,List<Object>> properties)
323         throws TaskException
324  {
325    super(REBUILD_TASK_CLASS, properties);
326
327    long     t = -1;
328    String   b = null;
329    String[] i = null;
330
331    for (final Map.Entry<TaskProperty,List<Object>> entry :
332         properties.entrySet())
333    {
334      final TaskProperty p = entry.getKey();
335      final String attrName = p.getAttributeName();
336      final List<Object> values = entry.getValue();
337
338      if (attrName.equalsIgnoreCase(ATTR_BASE_DN))
339      {
340        b = parseString(p, values, b);
341      }
342      else if (attrName.equalsIgnoreCase(ATTR_INDEX))
343      {
344        i = parseStrings(p, values, i);
345      }
346      else if (attrName.equalsIgnoreCase(ATTR_MAX_THREADS))
347      {
348        t = parseLong(p, values, t);
349      }
350    }
351
352    if (b == null)
353    {
354      throw new TaskException(ERR_REBUILD_TASK_NO_BASE_DN.get(
355                                   getTaskEntryDN()));
356    }
357
358    if (i == null)
359    {
360      throw new TaskException(ERR_REBUILD_TASK_NO_INDEXES.get(
361                                   getTaskEntryDN()));
362    }
363
364    baseDN     = b;
365    indexes    = Collections.unmodifiableList(Arrays.asList(i));
366    maxThreads = (int) t;
367  }
368
369
370
371  /**
372   * {@inheritDoc}
373   */
374  @Override()
375  public String getTaskName()
376  {
377    return INFO_TASK_NAME_REBUILD.get();
378  }
379
380
381
382  /**
383   * {@inheritDoc}
384   */
385  @Override()
386  public String getTaskDescription()
387  {
388    return INFO_TASK_DESCRIPTION_REBUILD.get();
389  }
390
391
392
393  /**
394   * Retrieves the base DN for which to rebuild the specified indexes.
395   *
396   * @return  The base DN for which to rebuild the specified indexes.
397   */
398  public String getBaseDN()
399  {
400    return baseDN;
401  }
402
403
404
405  /**
406   * Retrieves the names of the indexes to be rebuilt.
407   *
408   * @return  The names of the indexes to be rebuilt.
409   */
410  public List<String> getIndexNames()
411  {
412    return indexes;
413  }
414
415
416
417  /**
418   * Retrieves the maximum number of concurrent threads that should be used when
419   * rebuilding the indexes.
420   *
421   * @return  The maximum number of concurrent threads that should be used when
422   *          rebuilding the indexes, or a value less than or equal to zero if
423   *          there is no limit on the number of threads that may be used.
424   */
425  public int getMaxRebuildThreads()
426  {
427    return maxThreads;
428  }
429
430
431
432  /**
433   * {@inheritDoc}
434   */
435  @Override()
436  protected List<String> getAdditionalObjectClasses()
437  {
438    return Arrays.asList(OC_REBUILD_TASK);
439  }
440
441
442
443  /**
444   * {@inheritDoc}
445   */
446  @Override()
447  protected List<Attribute> getAdditionalAttributes()
448  {
449    final ArrayList<Attribute> attrs = new ArrayList<Attribute>(3);
450
451    attrs.add(new Attribute(ATTR_BASE_DN, baseDN));
452    attrs.add(new Attribute(ATTR_INDEX, indexes));
453
454    if (maxThreads > 0)
455    {
456      attrs.add(new Attribute(ATTR_MAX_THREADS, String.valueOf(maxThreads)));
457    }
458
459    return attrs;
460  }
461
462
463
464  /**
465   * {@inheritDoc}
466   */
467  @Override()
468  public List<TaskProperty> getTaskSpecificProperties()
469  {
470    final List<TaskProperty> propList = Arrays.asList(
471         PROPERTY_BASE_DN,
472         PROPERTY_INDEX,
473         PROPERTY_MAX_THREADS);
474
475    return Collections.unmodifiableList(propList);
476  }
477
478
479
480  /**
481   * {@inheritDoc}
482   */
483  @Override()
484  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
485  {
486    final LinkedHashMap<TaskProperty,List<Object>> props =
487         new LinkedHashMap<TaskProperty,List<Object>>();
488
489    props.put(PROPERTY_BASE_DN,
490              Collections.<Object>unmodifiableList(Arrays.asList(baseDN)));
491
492    props.put(PROPERTY_INDEX,
493              Collections.<Object>unmodifiableList(indexes));
494
495    props.put(PROPERTY_MAX_THREADS,
496              Collections.<Object>unmodifiableList(Arrays.asList(
497                   Long.valueOf(maxThreads))));
498
499    props.putAll(super.getTaskPropertyValues());
500    return Collections.unmodifiableMap(props);
501  }
502}