001/*
002 * Copyright 2015-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.Validator.*;
041
042
043
044/**
045 * This class defines a Directory Proxy Server task that can be used to reload
046 * the contents of the global index.
047 * <BR>
048 * <BLOCKQUOTE>
049 *   <B>NOTE:</B>  This class, and other classes within the
050 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
051 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
052 *   server products.  These classes provide support for proprietary
053 *   functionality or for external specifications that are not considered stable
054 *   or mature enough to be guaranteed to work in an interoperable way with
055 *   other types of LDAP servers.
056 * </BLOCKQUOTE>
057 * <BR>
058 * The properties that are available for use with this type of task include:
059 * <UL>
060 *   <LI>The base DN for the entry-balancing request processor.</LI>
061 *   <LI>An optional set of attributes for which to reload the index
062 *       information.</LI>
063 *   <LI>A flag indicating whether to perform the reload in the background.</LI>
064 *   <LI>A flag indicating whether to reload entries from backend Directory
065 *       Server instances rather than a peer Directory Proxy Server
066 *       instance.</LI>
067 *   <LI>An optional maximum number of entries per second to access when
068 *       priming.</LI>
069 * </UL>
070 */
071@NotMutable()
072@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
073public final class ReloadGlobalIndexTask
074       extends Task
075{
076  /**
077   * The fully-qualified name of the Java class that is used for the re-encode
078   * entries task.
079   */
080  static final String RELOAD_GLOBAL_INDEX_TASK_CLASS =
081       "com.unboundid.directory.proxy.tasks.ReloadTask";
082
083
084
085  /**
086   * The name of the attribute used to indicate whether the reload should be
087   * done in the background.
088   */
089  private static final String ATTR_BACKGROUND_RELOAD =
090       "ds-task-reload-background";
091
092
093
094  /**
095   * The name of the attribute used to specify the base DN for the
096   * entry-balancing request processor.
097   */
098  private static final String ATTR_BASE_DN = "ds-task-reload-base-dn";
099
100
101
102  /**
103   * The name of the attribute used to specify the names of the attributes for
104   * which to reload the indexes.
105   */
106  private static final String ATTR_INDEX_NAME = "ds-task-reload-index-name";
107
108
109
110  /**
111   * The name of the attribute used to specify a target rate limit for the
112   * maximum number of entries per second.
113   */
114  private static final String ATTR_MAX_ENTRIES_PER_SECOND =
115       "ds-task-search-entry-per-second";
116
117
118
119  /**
120   * The name of the attribute used to indicate whether the data should be
121   * loaded from backend Directory Server instances rather than a peer Directory
122   * Proxy Server instance.
123   */
124  private static final String ATTR_RELOAD_FROM_DS = "ds-task-reload-from-ds";
125
126
127
128  /**
129   * The name of the object class used in reload global index task entries.
130   */
131  private static final String OC_RELOAD_GLOBAL_INDEX_TASK =
132       "ds-task-reload-index";
133
134
135
136  /**
137   * The task property that will be used for the request processor base DN.
138   */
139  static final TaskProperty PROPERTY_BACKGROUND_RELOAD = new TaskProperty(
140       ATTR_BACKGROUND_RELOAD,
141       INFO_DISPLAY_NAME_RELOAD_GLOBAL_INDEX_BACKGROUND.get(),
142       INFO_DESCRIPTION_RELOAD_GLOBAL_INDEX_BACKGROUND.get(), Boolean.class,
143       false, false, false);
144
145
146
147  /**
148   * The task property that will be used for the request processor base DN.
149   */
150  static final TaskProperty PROPERTY_BASE_DN = new TaskProperty(
151       ATTR_BASE_DN, INFO_DISPLAY_NAME_RELOAD_GLOBAL_INDEX_BASE_DN.get(),
152       INFO_DESCRIPTION_RELOAD_GLOBAL_INDEX_BASE_DN.get(), String.class, true,
153       false, false);
154
155
156
157  /**
158   * The task property that will be used for the request processor base DN.
159   */
160  static final TaskProperty PROPERTY_INDEX_NAME = new TaskProperty(
161       ATTR_INDEX_NAME, INFO_DISPLAY_NAME_RELOAD_GLOBAL_INDEX_ATTR_NAME.get(),
162       INFO_DESCRIPTION_RELOAD_GLOBAL_INDEX_ATTR_NAME.get(), String.class,
163       false, true, false);
164
165
166
167  /**
168   * The task property that will be used for the request processor base DN.
169   */
170  static final TaskProperty PROPERTY_MAX_ENTRIES_PER_SECOND = new TaskProperty(
171       ATTR_MAX_ENTRIES_PER_SECOND,
172       INFO_DISPLAY_NAME_RELOAD_GLOBAL_INDEX_MAX_ENTRIES_PER_SECOND.get(),
173       INFO_DESCRIPTION_RELOAD_GLOBAL_INDEX_MAX_ENTRIES_PER_SECOND.get(),
174       Long.class, false, false, false);
175
176
177
178  /**
179   * The task property that will be used for the request processor base DN.
180   */
181  static final TaskProperty PROPERTY_RELOAD_FROM_DS = new TaskProperty(
182       ATTR_RELOAD_FROM_DS,
183       INFO_DISPLAY_NAME_RELOAD_GLOBAL_INDEX_RELOAD_FROM_DS.get(),
184       INFO_DESCRIPTION_RELOAD_GLOBAL_INDEX_RELOAD_FROM_DS.get(), Boolean.class,
185       false, false, false);
186
187
188
189  /**
190   * The serial version UID for this serializable class.
191   */
192  private static final long serialVersionUID = 9152807987055252560L;
193
194
195
196  // Indicates whether to reload from backend Directory Server instances.
197  private final Boolean reloadFromDS;
198
199  // Indicates whether to reload in the background.
200  private final Boolean reloadInBackground;
201
202  // The names of the indexes to reload.
203  private final List<String> indexNames;
204
205  // The target maximum rate limit to use when loading entry data.
206  private final Long maxEntriesPerSecond;
207
208  // The base DN for the entry-balancing request processor.
209  private final String baseDN;
210
211
212
213  /**
214   * Creates a new uninitialized reload global index task instance which should
215   * only be used for obtaining general information about this task, including
216   * the task name, description, and supported properties.  Attempts to use a
217   * task created with this constructor for any other reason will likely fail.
218   */
219  public ReloadGlobalIndexTask()
220  {
221    reloadFromDS        = null;
222    reloadInBackground  = null;
223    indexNames          = null;
224    maxEntriesPerSecond = null;
225    baseDN              = null;
226  }
227
228
229
230
231  /**
232   * Creates a new reload global index task with the provided information.
233   *
234   * @param  taskID               The task ID to use for this task.  If it is
235   *                              {@code null} then a UUID will be generated for
236   *                              use as the task ID.
237   * @param  baseDN               The base DN of the entry-balancing request
238   *                              processor for which to reload index
239   *                              information.
240   * @param  indexNames           The names of the attributes for which to
241   *                              reload index data.  This may be {@code null}
242   *                              or empty to indicate that all indexes should
243   *                              be reloaded.
244   * @param  reloadFromDS         Indicates whether to load index data from
245   *                              backend Directory Server instances rather than
246   *                              a peer Directory Proxy Server instance.  This
247   *                              may be {@code null} to indicate that the
248   *                              Directory Proxy Server should automatically
249   *                              select the appropriate source for obtaining
250   *                              index data.
251   * @param  reloadInBackground   Indicates whether to perform the reload in
252   *                              the background, so that the task completes
253   *                              immediately.
254   * @param  maxEntriesPerSecond  The maximum target rate at which to reload
255   *                              index data (in entries per second).  A value
256   *                              of zero indicates no limit.  A value of
257   *                              {@code null} indicates that the Directory
258   *                              Proxy Server should attempt to determine the
259   *                              limit based on its configuration.
260   */
261  public ReloadGlobalIndexTask(final String taskID, final String baseDN,
262                               final List<String> indexNames,
263                               final Boolean reloadFromDS,
264                               final Boolean reloadInBackground,
265                               final Long maxEntriesPerSecond)
266  {
267    this(taskID, baseDN, indexNames, reloadFromDS, reloadInBackground,
268         maxEntriesPerSecond, null, null, null, null, null);
269  }
270
271
272
273  /**
274   * Creates a new reload global index task with the provided information.
275   *
276   * @param  taskID                  The task ID to use for this task.  If it is
277   *                                 {@code null} then a UUID will be generated
278   *                                 for use as the task ID.
279   * @param  baseDN                  The base DN of the entry-balancing request
280   *                                 processor for which to reload index
281   *                                 information.
282   * @param  indexNames              The names of the attributes for which to
283   *                                 reload index data.  This may be
284   *                                 {@code null} or empty to indicate that all
285   *                                 indexes should be reloaded.
286   * @param  reloadFromDS            Indicates whether to load index data from
287   *                                 backend Directory Server instances rather
288   *                                 than a peer Directory Proxy Server
289   *                                 instance.  This may be {@code null} to
290   *                                 indicate that the Directory Proxy Server
291   *                                 should automatically select the appropriate
292   *                                 source for obtaining index data.
293   * @param  reloadInBackground      Indicates whether to perform the reload in
294   *                                 the background, so that the task completes
295   *                                 immediately.
296   * @param  maxEntriesPerSecond     The maximum target rate at which to reload
297   *                                 index data (in entries per second).  A
298   *                                 value of zero indicates no limit.  A value
299   *                                 of {@code null} indicates that the
300   *                                 Directory Proxy Server should attempt to
301   *                                 determine the limit based on its
302   *                                 configuration.
303   * @param  scheduledStartTime      The time that this task should start
304   *                                 running.
305   * @param  dependencyIDs           The list of task IDs that will be required
306   *                                 to complete before this task will be
307   *                                 eligible to start.
308   * @param  failedDependencyAction  Indicates what action should be taken if
309   *                                 any of the dependencies for this task do
310   *                                 not complete successfully.
311   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
312   *                                 that should be notified when this task
313   *                                 completes.
314   * @param  notifyOnError           The list of e-mail addresses of individuals
315   *                                 that should be notified if this task does
316   *                                 not complete successfully.
317   */
318  public ReloadGlobalIndexTask(final String taskID, final String baseDN,
319              final List<String> indexNames, final Boolean reloadFromDS,
320              final Boolean reloadInBackground, final Long maxEntriesPerSecond,
321              final Date scheduledStartTime,
322              final List<String> dependencyIDs,
323              final FailedDependencyAction failedDependencyAction,
324              final List<String> notifyOnCompletion,
325              final List<String> notifyOnError)
326  {
327    super(taskID, RELOAD_GLOBAL_INDEX_TASK_CLASS, scheduledStartTime,
328         dependencyIDs, failedDependencyAction, notifyOnCompletion,
329         notifyOnError);
330
331    ensureNotNull(baseDN);
332
333    this.baseDN              = baseDN;
334    this.reloadFromDS        = reloadFromDS;
335    this.reloadInBackground  = reloadInBackground;
336    this.maxEntriesPerSecond = maxEntriesPerSecond;
337
338    if (indexNames == null)
339    {
340      this.indexNames = Collections.emptyList();
341    }
342    else
343    {
344      this.indexNames = Collections.unmodifiableList(
345           new ArrayList<String>(indexNames));
346    }
347  }
348
349
350
351  /**
352   * Creates a new reload global index task from the provided entry.
353   *
354   * @param  entry  The entry to use to create this reload global index task.
355   *
356   * @throws  TaskException  If the provided entry cannot be parsed as a reload
357   *                         global index task entry.
358   */
359  public ReloadGlobalIndexTask(final Entry entry)
360         throws TaskException
361  {
362    super(entry);
363
364    // Get the base DN.  It must be present.
365    baseDN = entry.getAttributeValue(ATTR_BASE_DN);
366    if (baseDN == null)
367    {
368      throw new TaskException(
369           ERR_RELOAD_GLOBAL_INDEX_MISSING_REQUIRED_ATTR.get(ATTR_BASE_DN));
370    }
371
372    // Get the names of the indexes to reload.  It may be empty or null.
373    final String[] nameArray = entry.getAttributeValues(ATTR_INDEX_NAME);
374    if ((nameArray == null) || (nameArray.length == 0))
375    {
376      indexNames = Collections.emptyList();
377    }
378    else
379    {
380      indexNames = Collections.unmodifiableList(Arrays.asList(nameArray));
381    }
382
383    // Get the flag indicating whether to reload from backend Directory Server
384    // instances.
385    reloadFromDS = entry.getAttributeValueAsBoolean(ATTR_RELOAD_FROM_DS);
386
387    // Get the flag indicating whether to reload in a background thread.
388    reloadInBackground =
389         entry.getAttributeValueAsBoolean(ATTR_BACKGROUND_RELOAD);
390
391    // Get the value specifying the maximum reload rate in entries per second.
392    maxEntriesPerSecond =
393         entry.getAttributeValueAsLong(ATTR_MAX_ENTRIES_PER_SECOND);
394  }
395
396
397
398  /**
399   * Creates a new reload global index task from the provided set of task
400   * properties.
401   *
402   * @param  properties  The set of task properties and their corresponding
403   *                     values to use for the task.  It must not be
404   *                     {@code null}.
405   *
406   * @throws  TaskException  If the provided set of properties cannot be used to
407   *                         create a valid reload global index task.
408   */
409  public ReloadGlobalIndexTask(final Map<TaskProperty,List<Object>> properties)
410         throws TaskException
411  {
412    super(RELOAD_GLOBAL_INDEX_TASK_CLASS, properties);
413
414    final List<String> attrs = new ArrayList<String>(10);
415    Boolean background   = null;
416    Boolean fromDS       = null;
417    Long    maxPerSecond = null;
418    String  baseDNStr    = null;
419
420    for (final Map.Entry<TaskProperty,List<Object>> e : properties.entrySet())
421    {
422      final TaskProperty p = e.getKey();
423      final String attrName = p.getAttributeName();
424      final List<Object> values = e.getValue();
425
426      if (attrName.equalsIgnoreCase(ATTR_BASE_DN))
427      {
428        baseDNStr = parseString(p, values, null);
429      }
430      else if (attrName.equalsIgnoreCase(ATTR_INDEX_NAME))
431      {
432        final String[] nameArray = parseStrings(p, values, null);
433        if (nameArray != null)
434        {
435          attrs.addAll(Arrays.asList(nameArray));
436        }
437      }
438      else if (attrName.equalsIgnoreCase(ATTR_RELOAD_FROM_DS))
439      {
440        fromDS = parseBoolean(p, values, null);
441      }
442      else if (attrName.equalsIgnoreCase(ATTR_BACKGROUND_RELOAD))
443      {
444        background = parseBoolean(p, values, null);
445      }
446      else if (attrName.equalsIgnoreCase(ATTR_MAX_ENTRIES_PER_SECOND))
447      {
448        maxPerSecond = parseLong(p, values, null);
449      }
450    }
451
452    if (baseDNStr == null)
453    {
454      throw new TaskException(
455           ERR_RELOAD_GLOBAL_INDEX_MISSING_REQUIRED_PROPERTY.get(ATTR_BASE_DN));
456    }
457
458    baseDN              = baseDNStr;
459    indexNames          = Collections.unmodifiableList(attrs);
460    reloadFromDS        = fromDS;
461    reloadInBackground  = background;
462    maxEntriesPerSecond = maxPerSecond;
463  }
464
465
466
467  /**
468   * {@inheritDoc}
469   */
470  @Override()
471  public String getTaskName()
472  {
473    return INFO_TASK_NAME_RELOAD_GLOBAL_INDEX.get();
474  }
475
476
477
478  /**
479   * {@inheritDoc}
480   */
481  @Override()
482  public String getTaskDescription()
483  {
484    return INFO_TASK_DESCRIPTION_RELOAD_GLOBAL_INDEX.get();
485  }
486
487
488
489  /**
490   * Retrieves the base DN of the entry-balancing request processor for which to
491   * reload index data.
492   *
493   * @return  The base DN of the entry-balancing request processor for which to
494   *          reload index data.
495   */
496  public String getBaseDN()
497  {
498    return baseDN;
499  }
500
501
502
503  /**
504   * Retrieves the names of the indexes to be reloaded.
505   *
506   * @return  The names of the indexes to be reloaded, or an empty list if the
507   *          Directory Proxy Server should reload all indexes.
508   */
509  public List<String> getIndexNames()
510  {
511    return indexNames;
512  }
513
514
515
516  /**
517   * Indicates whether to reload index information from backend Directory
518   * Servers rather than a peer Directory Proxy Server.
519   *
520   * @return  {@code true} if the index information should be reloaded from
521   *          backend Directory Servers, {@code false} if the index information
522   *          should be reloaded from a peer Directory Proxy Server instance, or
523   *          {@code null} if the Directory Proxy Server should automatically
524   *          determine the reload data source.
525   */
526  public Boolean reloadFromDS()
527  {
528    return reloadFromDS;
529  }
530
531
532
533  /**
534   * Indicates whether to perform the index reload processing in the background.
535   *
536   * @return  {@code true} if the index reload processing should be performed
537   *          in the background (so that the task completes immediately),
538   *          {@code false} if not, or {@code null} if the Directory Proxy
539   *          Server should determine whether to perform the reload in the
540   *          background.
541   */
542  public Boolean reloadInBackground()
543  {
544    return reloadInBackground;
545  }
546
547
548
549  /**
550   * Retrieves the maximum reload rate in entries per second, if defined.
551   *
552   * @return  The maximum rate at which to reload index data, in entries per
553   *          second, zero if no limit should be imposed, or {@code null} if the
554   *          Directory Proxy Server should determine the maximum reload rate.
555   */
556  public Long getMaxEntriesPerSecond()
557  {
558    return maxEntriesPerSecond;
559  }
560
561
562
563  /**
564   * {@inheritDoc}
565   */
566  @Override()
567  protected List<String> getAdditionalObjectClasses()
568  {
569    return Arrays.asList(OC_RELOAD_GLOBAL_INDEX_TASK);
570  }
571
572
573
574  /**
575   * {@inheritDoc}
576   */
577  @Override()
578  protected List<Attribute> getAdditionalAttributes()
579  {
580    final ArrayList<Attribute> attrList = new ArrayList<Attribute>(5);
581
582    attrList.add(new Attribute(ATTR_BASE_DN, baseDN));
583
584    if (! indexNames.isEmpty())
585    {
586      attrList.add(new Attribute(ATTR_INDEX_NAME, indexNames));
587    }
588
589    if (reloadFromDS != null)
590    {
591      attrList.add(new Attribute(ATTR_RELOAD_FROM_DS,
592           String.valueOf(reloadFromDS)));
593    }
594
595    if (reloadInBackground != null)
596    {
597      attrList.add(new Attribute(ATTR_BACKGROUND_RELOAD,
598           String.valueOf(reloadInBackground)));
599    }
600
601    if (maxEntriesPerSecond != null)
602    {
603      attrList.add(new Attribute(ATTR_MAX_ENTRIES_PER_SECOND,
604           String.valueOf(maxEntriesPerSecond)));
605    }
606
607    return attrList;
608  }
609
610
611
612  /**
613   * {@inheritDoc}
614   */
615  @Override()
616  public List<TaskProperty> getTaskSpecificProperties()
617  {
618    return Collections.unmodifiableList(Arrays.asList(
619         PROPERTY_BASE_DN,
620         PROPERTY_INDEX_NAME,
621         PROPERTY_RELOAD_FROM_DS,
622         PROPERTY_BACKGROUND_RELOAD,
623         PROPERTY_MAX_ENTRIES_PER_SECOND));
624  }
625
626
627
628  /**
629   * {@inheritDoc}
630   */
631  @Override()
632  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
633  {
634    final LinkedHashMap<TaskProperty,List<Object>> props =
635         new LinkedHashMap<TaskProperty,List<Object>>(15);
636
637    props.put(PROPERTY_BASE_DN,
638         Collections.<Object>unmodifiableList(Arrays.asList(baseDN)));
639    props.put(PROPERTY_INDEX_NAME,
640         Collections.<Object>unmodifiableList(indexNames));
641
642    if (reloadFromDS == null)
643    {
644      props.put(PROPERTY_RELOAD_FROM_DS,
645           Collections.emptyList());
646    }
647    else
648    {
649      props.put(PROPERTY_RELOAD_FROM_DS,
650           Collections.<Object>unmodifiableList(Arrays.asList(reloadFromDS)));
651    }
652
653    if (reloadInBackground == null)
654    {
655      props.put(PROPERTY_BACKGROUND_RELOAD,
656           Collections.emptyList());
657    }
658    else
659    {
660      props.put(PROPERTY_BACKGROUND_RELOAD,
661           Collections.<Object>unmodifiableList(Arrays.asList(
662                reloadInBackground)));
663    }
664
665    if (maxEntriesPerSecond == null)
666    {
667      props.put(PROPERTY_MAX_ENTRIES_PER_SECOND,
668           Collections.emptyList());
669    }
670    else
671    {
672      props.put(PROPERTY_MAX_ENTRIES_PER_SECOND,
673           Collections.<Object>unmodifiableList(
674                Arrays.asList(maxEntriesPerSecond)));
675    }
676
677    props.putAll(super.getTaskPropertyValues());
678    return Collections.unmodifiableMap(props);
679  }
680}