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.Debug;
036import com.unboundid.util.NotMutable;
037import com.unboundid.util.ThreadSafety;
038import com.unboundid.util.ThreadSafetyLevel;
039import com.unboundid.util.Validator;
040
041import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*;
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
053 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
054 *   for proprietary functionality or for external specifications that are not
055 *   considered stable or mature enough to be guaranteed to work in an
056 *   interoperable way with 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    this(taskID, baseDN, indexes, maxThreads, scheduledStartTime, dependencyIDs,
240         failedDependencyAction, null, notifyOnCompletion, null, notifyOnError,
241         null, null, null);
242  }
243
244
245
246  /**
247   * Creates a new rebuild task with the provided information.
248   *
249   * @param  taskID                  The task ID to use for this task.  If it is
250   *                                 {@code null} then a UUID will be generated
251   *                                 for use as the task ID.
252   * @param  baseDN                  The base DN for which to rebuild the index.
253   *                                 It must refer to a base DN for a Berkeley
254   *                                 DB Java Edition backend.  It must not be
255   *                                 {@code null}.
256   * @param  indexes                 A list containing the names of the indexes
257   *                                 to rebuild.  It must not be {@code null} or
258   *                                 empty.
259   * @param  maxThreads              The maximum number of concurrent threads to
260   *                                 use while performing the rebuild.  A value
261   *                                 less than or equal to zero indicates that
262   *                                 there is no limit to the number of threads
263   *                                 that may be used.
264   * @param  scheduledStartTime      The time that this task should start
265   *                                 running.
266   * @param  dependencyIDs           The list of task IDs that will be required
267   *                                 to complete before this task will be
268   *                                 eligible to start.
269   * @param  failedDependencyAction  Indicates what action should be taken if
270   *                                 any of the dependencies for this task do
271   *                                 not complete successfully.
272   * @param  notifyOnStart           The list of e-mail addresses of individuals
273   *                                 that should be notified when this task
274   *                                 starts running.
275   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
276   *                                 that should be notified when this task
277   *                                 completes.
278   * @param  notifyOnSuccess         The list of e-mail addresses of individuals
279   *                                 that should be notified if this task
280   *                                 completes successfully.
281   * @param  notifyOnError           The list of e-mail addresses of individuals
282   *                                 that should be notified if this task does
283   *                                 not complete successfully.
284   * @param  alertOnStart            Indicates whether the server should send an
285   *                                 alert notification when this task starts.
286   * @param  alertOnSuccess          Indicates whether the server should send an
287   *                                 alert notification if this task completes
288   *                                 successfully.
289   * @param  alertOnError            Indicates whether the server should send an
290   *                                 alert notification if this task fails to
291   *                                 complete successfully.
292   */
293  public RebuildTask(final String taskID, final String baseDN,
294                     final List<String> indexes, final int maxThreads,
295                     final Date scheduledStartTime,
296                     final List<String> dependencyIDs,
297                     final FailedDependencyAction failedDependencyAction,
298                     final List<String> notifyOnStart,
299                     final List<String> notifyOnCompletion,
300                     final List<String> notifyOnSuccess,
301                     final List<String> notifyOnError,
302                     final Boolean alertOnStart, final Boolean alertOnSuccess,
303                     final Boolean alertOnError)
304  {
305    super(taskID, REBUILD_TASK_CLASS, scheduledStartTime, dependencyIDs,
306         failedDependencyAction, notifyOnStart, notifyOnCompletion,
307         notifyOnSuccess, notifyOnError, alertOnStart, alertOnSuccess,
308         alertOnError);
309
310    Validator.ensureNotNull(baseDN, indexes);
311    Validator.ensureFalse(indexes.isEmpty(),
312         "RebuildTask.indexes must not be empty.");
313
314    this.baseDN     = baseDN;
315    this.indexes    = Collections.unmodifiableList(indexes);
316    this.maxThreads = maxThreads;
317  }
318
319
320
321  /**
322   * Creates a new rebuild task from the provided entry.
323   *
324   * @param  entry  The entry to use to create this rebuild task.
325   *
326   * @throws  TaskException  If the provided entry cannot be parsed as a rebuild
327   *                         task entry.
328   */
329  public RebuildTask(final Entry entry)
330         throws TaskException
331  {
332    super(entry);
333
334
335    // Get the base DN.  It must be present.
336    baseDN = entry.getAttributeValue(ATTR_BASE_DN);
337    if (baseDN == null)
338    {
339      throw new TaskException(ERR_REBUILD_TASK_NO_BASE_DN.get(
340                                   getTaskEntryDN()));
341    }
342
343
344    // Get the names of the indexes to rebuild.  It must be present.
345    final String[] indexArray = entry.getAttributeValues(ATTR_INDEX);
346    if ((indexArray == null) || (indexArray.length == 0))
347    {
348      throw new TaskException(ERR_REBUILD_TASK_NO_INDEXES.get(
349                                   getTaskEntryDN()));
350    }
351    else
352    {
353      indexes = Collections.unmodifiableList(Arrays.asList(indexArray));
354    }
355
356
357    // Get the maximum number of threads to use.
358    final String threadsStr = entry.getAttributeValue(ATTR_MAX_THREADS);
359    if (threadsStr == null)
360    {
361      maxThreads = -1;
362    }
363    else
364    {
365      try
366      {
367        maxThreads = Integer.parseInt(threadsStr);
368      }
369      catch (final Exception e)
370      {
371        Debug.debugException(e);
372        throw new TaskException(ERR_REBUILD_TASK_INVALID_MAX_THREADS.get(
373                                     getTaskEntryDN(), threadsStr), e);
374      }
375    }
376  }
377
378
379
380  /**
381   * Creates a new rebuild task from the provided set of task properties.
382   *
383   * @param  properties  The set of task properties and their corresponding
384   *                     values to use for the task.  It must not be
385   *                     {@code null}.
386   *
387   * @throws  TaskException  If the provided set of properties cannot be used to
388   *                         create a valid rebuild task.
389   */
390  public RebuildTask(final Map<TaskProperty,List<Object>> properties)
391         throws TaskException
392  {
393    super(REBUILD_TASK_CLASS, properties);
394
395    long     t = -1;
396    String   b = null;
397    String[] i = null;
398
399    for (final Map.Entry<TaskProperty,List<Object>> entry :
400         properties.entrySet())
401    {
402      final TaskProperty p = entry.getKey();
403      final String attrName = p.getAttributeName();
404      final List<Object> values = entry.getValue();
405
406      if (attrName.equalsIgnoreCase(ATTR_BASE_DN))
407      {
408        b = parseString(p, values, b);
409      }
410      else if (attrName.equalsIgnoreCase(ATTR_INDEX))
411      {
412        i = parseStrings(p, values, i);
413      }
414      else if (attrName.equalsIgnoreCase(ATTR_MAX_THREADS))
415      {
416        t = parseLong(p, values, t);
417      }
418    }
419
420    if (b == null)
421    {
422      throw new TaskException(ERR_REBUILD_TASK_NO_BASE_DN.get(
423                                   getTaskEntryDN()));
424    }
425
426    if (i == null)
427    {
428      throw new TaskException(ERR_REBUILD_TASK_NO_INDEXES.get(
429                                   getTaskEntryDN()));
430    }
431
432    baseDN     = b;
433    indexes    = Collections.unmodifiableList(Arrays.asList(i));
434    maxThreads = (int) t;
435  }
436
437
438
439  /**
440   * {@inheritDoc}
441   */
442  @Override()
443  public String getTaskName()
444  {
445    return INFO_TASK_NAME_REBUILD.get();
446  }
447
448
449
450  /**
451   * {@inheritDoc}
452   */
453  @Override()
454  public String getTaskDescription()
455  {
456    return INFO_TASK_DESCRIPTION_REBUILD.get();
457  }
458
459
460
461  /**
462   * Retrieves the base DN for which to rebuild the specified indexes.
463   *
464   * @return  The base DN for which to rebuild the specified indexes.
465   */
466  public String getBaseDN()
467  {
468    return baseDN;
469  }
470
471
472
473  /**
474   * Retrieves the names of the indexes to be rebuilt.
475   *
476   * @return  The names of the indexes to be rebuilt.
477   */
478  public List<String> getIndexNames()
479  {
480    return indexes;
481  }
482
483
484
485  /**
486   * Retrieves the maximum number of concurrent threads that should be used when
487   * rebuilding the indexes.
488   *
489   * @return  The maximum number of concurrent threads that should be used when
490   *          rebuilding the indexes, or a value less than or equal to zero if
491   *          there is no limit on the number of threads that may be used.
492   */
493  public int getMaxRebuildThreads()
494  {
495    return maxThreads;
496  }
497
498
499
500  /**
501   * {@inheritDoc}
502   */
503  @Override()
504  protected List<String> getAdditionalObjectClasses()
505  {
506    return Collections.singletonList(OC_REBUILD_TASK);
507  }
508
509
510
511  /**
512   * {@inheritDoc}
513   */
514  @Override()
515  protected List<Attribute> getAdditionalAttributes()
516  {
517    final ArrayList<Attribute> attrs = new ArrayList<>(3);
518
519    attrs.add(new Attribute(ATTR_BASE_DN, baseDN));
520    attrs.add(new Attribute(ATTR_INDEX, indexes));
521
522    if (maxThreads > 0)
523    {
524      attrs.add(new Attribute(ATTR_MAX_THREADS, String.valueOf(maxThreads)));
525    }
526
527    return attrs;
528  }
529
530
531
532  /**
533   * {@inheritDoc}
534   */
535  @Override()
536  public List<TaskProperty> getTaskSpecificProperties()
537  {
538    final List<TaskProperty> propList = Arrays.asList(
539         PROPERTY_BASE_DN,
540         PROPERTY_INDEX,
541         PROPERTY_MAX_THREADS);
542
543    return Collections.unmodifiableList(propList);
544  }
545
546
547
548  /**
549   * {@inheritDoc}
550   */
551  @Override()
552  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
553  {
554    final LinkedHashMap<TaskProperty,List<Object>> props =
555         new LinkedHashMap<>(10);
556
557    props.put(PROPERTY_BASE_DN,
558              Collections.<Object>singletonList(baseDN));
559
560    props.put(PROPERTY_INDEX,
561              Collections.<Object>unmodifiableList(indexes));
562
563    props.put(PROPERTY_MAX_THREADS,
564              Collections.<Object>singletonList((long) maxThreads));
565
566    props.putAll(super.getTaskPropertyValues());
567    return Collections.unmodifiableMap(props);
568  }
569}