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