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