001/*
002 * Copyright 2013-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.NotMutable;
036import com.unboundid.util.StaticUtils;
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 cause entries
047 * contained in a local DB backend to be re-encoded, which may be used to
048 * apply any configuration changes that affect the encoding of that entry (e.g.,
049 * if the entry should be encrypted, hashed, compressed, or fully or partially
050 * uncached; or if these settings should be reverted).
051 * <BR>
052 * <BLOCKQUOTE>
053 *   <B>NOTE:</B>  This class, and other classes within the
054 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
055 *   supported for use against Ping Identity, UnboundID, and
056 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
057 *   for proprietary functionality or for external specifications that are not
058 *   considered stable or mature enough to be guaranteed to work in an
059 *   interoperable way with other types of LDAP servers.
060 * </BLOCKQUOTE>
061 * <BR>
062 * The properties that are available for use with this type of task include:
063 * <UL>
064 *   <LI>The backend ID of the backend in which entries should be re-encoded.
065 *       This must be provided.</LI>
066 *   <LI>The base DN of a branch of entries to include in the re-encode
067 *       processing.</LI>
068 *   <LI>The base DN of a branch of entries to exclude from the re-encode
069 *       processing.</LI>
070 *   <LI>A filter to use to identify entries to include in the re-encode
071 *       processing.</LI>
072 *   <LI>A filter to use to identify entries to exclude from the re-encode
073 *       processing.</LI>
074 *   <LI>The maximum rate at which to re-encode entries, in number of entries
075 *       per second.</LI>
076 *   <LI>An indication as to whether to skip entries that are fully
077 *       uncached.</LI>
078 *   <LI>An indication as to whether to skip entries that are partially
079 *       uncached.</LI>
080 * </UL>
081 */
082@NotMutable()
083@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
084public final class ReEncodeEntriesTask
085       extends Task
086{
087  /**
088   * The fully-qualified name of the Java class that is used for the re-encode
089   * entries task.
090   */
091  static final String RE_ENCODE_ENTRIES_TASK_CLASS =
092       "com.unboundid.directory.server.tasks.ReEncodeEntriesTask";
093
094
095  /**
096   * The name of the attribute used to specify the backend ID containing the
097   * entries to re-encode.
098   */
099  private static final String ATTR_BACKEND_ID = "ds-task-reencode-backend-id";
100
101
102  /**
103   * The name of the attribute used to specify the include branch(es).
104   */
105  private static final String ATTR_INCLUDE_BRANCH =
106       "ds-task-reencode-include-branch";
107
108
109  /**
110   * The name of the attribute used to specify the exclude branch(es).
111   */
112  private static final String ATTR_EXCLUDE_BRANCH =
113       "ds-task-reencode-exclude-branch";
114
115
116  /**
117   * The name of the attribute used to specify the include filter(s).
118   */
119  private static final String ATTR_INCLUDE_FILTER =
120       "ds-task-reencode-include-filter";
121
122
123  /**
124   * The name of the attribute used to specify the exclude filter(s).
125   */
126  private static final String ATTR_EXCLUDE_FILTER =
127       "ds-task-reencode-exclude-filter";
128
129
130  /**
131   * The name of the attribute used to specify the maximum re-encode rate in
132   * entries per second.
133   */
134  private static final String ATTR_MAX_ENTRIES_PER_SECOND =
135       "ds-task-reencode-max-entries-per-second";
136
137
138  /**
139   * The name of the attribute used to specify whether to skip fully uncached
140   * entries.
141   */
142  private static final String ATTR_SKIP_FULLY_UNCACHED =
143       "ds-task-reencode-skip-fully-uncached-entries";
144
145
146  /**
147   * The name of the attribute used to specify whether to skip partially
148   * uncached entries.
149   */
150  private static final String ATTR_SKIP_PARTIALLY_UNCACHED =
151       "ds-task-reencode-skip-partially-uncached-entries";
152
153
154  /**
155   * The name of the object class used in re-encode entries task entries.
156   */
157  private static final String OC_REENCODE_ENTRIES_TASK =
158       "ds-task-reencode";
159
160
161  /**
162   * The task property that will be used for the backend ID.
163   */
164  static final TaskProperty PROPERTY_BACKEND_ID =
165       new TaskProperty(ATTR_BACKEND_ID,
166            INFO_DISPLAY_NAME_REENCODE_BACKEND_ID.get(),
167            INFO_DESCRIPTION_REENCODE_BACKEND_ID.get(),
168          String.class, true, false, false);
169
170
171
172  /**
173   * The task property that will be used for the include branch(es).
174   */
175  private static final TaskProperty PROPERTY_INCLUDE_BRANCH =
176     new TaskProperty(ATTR_INCLUDE_BRANCH,
177          INFO_DISPLAY_NAME_REENCODE_INCLUDE_BRANCH.get(),
178          INFO_DESCRIPTION_REENCODE_INCLUDE_BRANCH.get(),
179          String.class, false, true, false);
180
181
182
183  /**
184   * The task property that will be used for the exclude branch(es).
185   */
186  private static final TaskProperty PROPERTY_EXCLUDE_BRANCH =
187     new TaskProperty(ATTR_EXCLUDE_BRANCH,
188          INFO_DISPLAY_NAME_REENCODE_EXCLUDE_BRANCH.get(),
189          INFO_DESCRIPTION_REENCODE_EXCLUDE_BRANCH.get(),
190          String.class, false, true, false);
191
192
193
194  /**
195   * The task property that will be used for the include filter(s).
196   */
197  private static final TaskProperty PROPERTY_INCLUDE_FILTER =
198     new TaskProperty(ATTR_INCLUDE_FILTER,
199          INFO_DISPLAY_NAME_REENCODE_INCLUDE_FILTER.get(),
200          INFO_DESCRIPTION_REENCODE_INCLUDE_FILTER.get(),
201          String.class, false, true, false);
202
203
204
205  /**
206   * The task property that will be used for the exclude filter(s).
207   */
208  private static final TaskProperty PROPERTY_EXCLUDE_FILTER =
209     new TaskProperty(ATTR_EXCLUDE_FILTER,
210          INFO_DISPLAY_NAME_REENCODE_EXCLUDE_FILTER.get(),
211          INFO_DESCRIPTION_REENCODE_EXCLUDE_FILTER.get(),
212          String.class, false, true, false);
213
214
215
216  /**
217   * The task property that will be used for the maximum reencode rate.
218   */
219  private static final TaskProperty PROPERTY_MAX_ENTRIES_PER_SECOND =
220     new TaskProperty(ATTR_MAX_ENTRIES_PER_SECOND,
221          INFO_DISPLAY_NAME_REENCODE_MAX_ENTRIES_PER_SECOND.get(),
222          INFO_DESCRIPTION_REENCODE_MAX_ENTRIES_PER_SECOND.get(),
223          Long.class, false, false, false);
224
225
226
227  /**
228   * The task property that will be used to indicate whether to skip fully
229   * uncached entries.
230   */
231  private static final TaskProperty PROPERTY_SKIP_FULLY_UNCACHED =
232     new TaskProperty(ATTR_SKIP_FULLY_UNCACHED,
233          INFO_DISPLAY_NAME_REENCODE_SKIP_FULLY_UNCACHED.get(),
234          INFO_DESCRIPTION_REENCODE_SKIP_FULLY_UNCACHED.get(),
235          Boolean.class, false, false, false);
236
237
238
239  /**
240   * The task property that will be used to indicate whether to skip partially
241   * uncached entries.
242   */
243  private static final TaskProperty PROPERTY_SKIP_PARTIALLY_UNCACHED =
244     new TaskProperty(ATTR_SKIP_PARTIALLY_UNCACHED,
245          INFO_DISPLAY_NAME_REENCODE_SKIP_PARTIALLY_UNCACHED.get(),
246          INFO_DESCRIPTION_REENCODE_SKIP_PARTIALLY_UNCACHED.get(),
247          Boolean.class, false, false, false);
248
249
250
251  /**
252   * The serial version UID for this serializable class.
253   */
254  private static final long serialVersionUID = 1804218099237094046L;
255
256
257
258  // Indicates whether to skip fully-uncached entries.
259  private final boolean skipFullyUncachedEntries;
260
261  // Indicates whether to skip partially-uncached entries.
262  private final boolean skipPartiallyUncachedEntries;
263
264  // The maximum number of entries to re-encode per second.
265  private final Long maxEntriesPerSecond;
266
267  // The list of exclude branch DNs.
268  private final List<String> excludeBranches;
269
270  // The list of exclude filters.
271  private final List<String> excludeFilters;
272
273  // The list of include branch DNs.
274  private final List<String> includeBranches;
275
276  // The list of include filters.
277  private final List<String> includeFilters;
278
279  // The backend ID for the backend containing entries to re-encode.
280  private final String backendID;
281
282
283
284  /**
285   * Creates a new uninitialized re-encode entries task instance which should
286   * only be used for obtaining general information about this task, including
287   * the task name, description, and supported properties.  Attempts to use a
288   * task created with this constructor for any other reason will likely fail.
289   */
290  public ReEncodeEntriesTask()
291  {
292    skipFullyUncachedEntries     = false;
293    skipPartiallyUncachedEntries = false;
294    maxEntriesPerSecond          = null;
295    excludeBranches              = null;
296    excludeFilters               = null;
297    includeBranches              = null;
298    includeFilters               = null;
299    backendID                    = null;
300  }
301
302
303
304  /**
305   * Creates a new re-encode entries task with the provided information.
306   *
307   * @param  taskID                        The task ID to use for this task.  If
308   *                                       it is {@code null} then a UUID will
309   *                                       be generated for use as the task ID.
310   * @param  backendID                     The backend ID of the backend
311   *                                       containing the entries to re-encode.
312   *                                       It must not be {@code null}.
313   * @param  includeBranches               A list containing the base DNs of
314   *                                       branches to include in re-encode
315   *                                       processing.  It may be {@code null}
316   *                                       or empty if there should not be any
317   *                                       include branches.
318   * @param  excludeBranches               A list containing the base DNs of
319   *                                       branches to exclude from re-encode
320   *                                       processing.  It may be {@code null}
321   *                                       or empty if there should not be any
322   *                                       exclude branches.
323   * @param  includeFilters                A list containing filters to use to
324   *                                       identify entries to include in
325   *                                       re-encode processing.  It may be
326   *                                       {@code null} or empty if there should
327   *                                       not be any include filters.
328   * @param  excludeFilters                A list containing filters to use to
329   *                                       identify entries to exclude from
330   *                                       re-encode processing.  It may be
331   *                                       {@code null} or empty if there should
332   *                                       not be any exclude filters.
333   * @param  maxEntriesPerSecond           The maximum number of entries to
334   *                                       re-encode per second.  It may be
335   *                                       {@code null} to indicate that no
336   *                                       limit should be imposed.
337   * @param  skipFullyUncachedEntries      Indicates whether to skip re-encode
338   *                                       processing for entries that are fully
339   *                                       uncached.
340   * @param  skipPartiallyUncachedEntries  Indicates whether to skip re-encode
341   *                                       processing for entries that contain
342   *                                       a mix of cached and uncached
343   *                                       attributes.
344   */
345  public ReEncodeEntriesTask(final String taskID,
346                             final String backendID,
347                             final List<String> includeBranches,
348                             final List<String> excludeBranches,
349                             final List<String> includeFilters,
350                             final List<String> excludeFilters,
351                             final Long maxEntriesPerSecond,
352                             final boolean skipFullyUncachedEntries,
353                             final boolean skipPartiallyUncachedEntries)
354  {
355    this(taskID, backendID, includeBranches, excludeBranches, includeFilters,
356         excludeFilters, maxEntriesPerSecond, skipFullyUncachedEntries,
357         skipPartiallyUncachedEntries, null, null, null, null, null);
358  }
359
360
361
362  /**
363   * Creates a new re-encode entries task with the provided information.
364   *
365   * @param  taskID                        The task ID to use for this task.  If
366   *                                       it is {@code null} then a UUID will
367   *                                       be generated for use as the task ID.
368   * @param  backendID                     The backend ID of the backend
369   *                                       containing the entries to re-encode.
370   *                                       It must not be {@code null}.
371   * @param  includeBranches               A list containing the base DNs of
372   *                                       branches to include in re-encode
373   *                                       processing.  It may be {@code null}
374   *                                       or empty if there should not be any
375   *                                       include branches.
376   * @param  excludeBranches               A list containing the base DNs of
377   *                                       branches to exclude from re-encode
378   *                                       processing.  It may be {@code null}
379   *                                       or empty if there should not be any
380   *                                       exclude branches.
381   * @param  includeFilters                A list containing filters to use to
382   *                                       identify entries to include in
383   *                                       re-encode processing.  It may be
384   *                                       {@code null} or empty if there should
385   *                                       not be any include filters.
386   * @param  excludeFilters                A list containing filters to use to
387   *                                       identify entries to exclude from
388   *                                       re-encode processing.  It may be
389   *                                       {@code null} or empty if there should
390   *                                       not be any exclude filters.
391   * @param  maxEntriesPerSecond           The maximum number of entries to
392   *                                       re-encode per second.  It may be
393   *                                       {@code null} to indicate that no
394   *                                       limit should be imposed.
395   * @param  skipFullyUncachedEntries      Indicates whether to skip re-encode
396   *                                       processing for entries that are fully
397   *                                       uncached.
398   * @param  skipPartiallyUncachedEntries  Indicates whether to skip re-encode
399   *                                       processing for entries that contain
400   *                                       a mix of cached and uncached
401   *                                       attributes.
402   * @param  scheduledStartTime            The time that this task should start
403   *                                       running.
404   * @param  dependencyIDs                 The list of task IDs that will be
405   *                                       required to complete before this task
406   *                                       will be eligible to start.
407   * @param  failedDependencyAction        Indicates what action should be taken
408   *                                       if any of the dependencies for this
409   *                                       task do not complete successfully.
410   * @param  notifyOnCompletion            The list of e-mail addresses of
411   *                                       individuals that should be notified
412   *                                       when this task completes.
413   * @param  notifyOnError                 The list of e-mail addresses of
414   *                                       individuals that should be notified
415   *                                       if this task does not complete
416   *                                       successfully.
417   */
418  public ReEncodeEntriesTask(final String taskID, final String backendID,
419              final List<String> includeBranches,
420              final List<String> excludeBranches,
421              final List<String> includeFilters,
422              final List<String> excludeFilters,
423              final Long maxEntriesPerSecond,
424              final boolean skipFullyUncachedEntries,
425              final boolean skipPartiallyUncachedEntries,
426              final Date scheduledStartTime,
427              final List<String> dependencyIDs,
428              final FailedDependencyAction failedDependencyAction,
429              final List<String> notifyOnCompletion,
430              final List<String> notifyOnError)
431  {
432    this(taskID, backendID, includeBranches, excludeBranches, includeFilters,
433         excludeFilters, maxEntriesPerSecond, skipFullyUncachedEntries,
434         skipPartiallyUncachedEntries, scheduledStartTime, dependencyIDs,
435         failedDependencyAction, null, notifyOnCompletion, null,
436         notifyOnError, null, null, null);
437  }
438
439
440
441  /**
442   * Creates a new re-encode entries task with the provided information.
443   *
444   * @param  taskID                        The task ID to use for this task.  If
445   *                                       it is {@code null} then a UUID will
446   *                                       be generated for use as the task ID.
447   * @param  backendID                     The backend ID of the backend
448   *                                       containing the entries to re-encode.
449   *                                       It must not be {@code null}.
450   * @param  includeBranches               A list containing the base DNs of
451   *                                       branches to include in re-encode
452   *                                       processing.  It may be {@code null}
453   *                                       or empty if there should not be any
454   *                                       include branches.
455   * @param  excludeBranches               A list containing the base DNs of
456   *                                       branches to exclude from re-encode
457   *                                       processing.  It may be {@code null}
458   *                                       or empty if there should not be any
459   *                                       exclude branches.
460   * @param  includeFilters                A list containing filters to use to
461   *                                       identify entries to include in
462   *                                       re-encode processing.  It may be
463   *                                       {@code null} or empty if there should
464   *                                       not be any include filters.
465   * @param  excludeFilters                A list containing filters to use to
466   *                                       identify entries to exclude from
467   *                                       re-encode processing.  It may be
468   *                                       {@code null} or empty if there should
469   *                                       not be any exclude filters.
470   * @param  maxEntriesPerSecond           The maximum number of entries to
471   *                                       re-encode per second.  It may be
472   *                                       {@code null} to indicate that no
473   *                                       limit should be imposed.
474   * @param  skipFullyUncachedEntries      Indicates whether to skip re-encode
475   *                                       processing for entries that are fully
476   *                                       uncached.
477   * @param  skipPartiallyUncachedEntries  Indicates whether to skip re-encode
478   *                                       processing for entries that contain
479   *                                       a mix of cached and uncached
480   *                                       attributes.
481   * @param  scheduledStartTime            The time that this task should start
482   *                                       running.
483   * @param  dependencyIDs                 The list of task IDs that will be
484   *                                       required to complete before this task
485   *                                       will be eligible to start.
486   * @param  failedDependencyAction        Indicates what action should be taken
487   *                                       if any of the dependencies for this
488   *                                       task do not complete successfully.
489   * @param  notifyOnStart                 The list of e-mail addresses of
490   *                                       individuals that should be notified
491   *                                       when this task starts running.
492   * @param  notifyOnCompletion            The list of e-mail addresses of
493   *                                       individuals that should be notified
494   *                                       when this task completes.
495   * @param  notifyOnSuccess               The list of e-mail addresses of
496   *                                       individuals that should be notified
497   *                                       if this task completes successfully.
498   * @param  notifyOnError                 The list of e-mail addresses of
499   *                                       individuals that should be notified
500   *                                       if this task does not complete
501   *                                       successfully.
502   * @param  alertOnStart                  Indicates whether the server should
503   *                                       send an alert notification when this
504   *                                       task starts.
505   * @param  alertOnSuccess                Indicates whether the server should
506   *                                       send an alert notification if this
507   *                                       task completes successfully.
508   * @param  alertOnError                  Indicates whether the server should
509   *                                       send an alert notification if this
510   *                                       task fails to complete successfully.
511   */
512  public ReEncodeEntriesTask(final String taskID, final String backendID,
513              final List<String> includeBranches,
514              final List<String> excludeBranches,
515              final List<String> includeFilters,
516              final List<String> excludeFilters,
517              final Long maxEntriesPerSecond,
518              final boolean skipFullyUncachedEntries,
519              final boolean skipPartiallyUncachedEntries,
520              final Date scheduledStartTime,
521              final List<String> dependencyIDs,
522              final FailedDependencyAction failedDependencyAction,
523              final List<String> notifyOnStart,
524              final List<String> notifyOnCompletion,
525              final List<String> notifyOnSuccess,
526              final List<String> notifyOnError, final Boolean alertOnStart,
527              final Boolean alertOnSuccess, final Boolean alertOnError)
528  {
529    super(taskID, RE_ENCODE_ENTRIES_TASK_CLASS, scheduledStartTime,
530         dependencyIDs, failedDependencyAction, notifyOnStart,
531         notifyOnCompletion, notifyOnSuccess, notifyOnError, alertOnStart,
532         alertOnSuccess, alertOnError);
533
534    Validator.ensureNotNull(backendID);
535
536    this.backendID                    = backendID;
537    this.maxEntriesPerSecond          = maxEntriesPerSecond;
538    this.skipFullyUncachedEntries     = skipFullyUncachedEntries;
539    this.skipPartiallyUncachedEntries = skipPartiallyUncachedEntries;
540
541    if ((includeBranches == null) || includeBranches.isEmpty())
542    {
543      this.includeBranches = Collections.emptyList();
544    }
545    else
546    {
547      this.includeBranches = Collections.unmodifiableList(includeBranches);
548    }
549
550    if ((excludeBranches == null) || excludeBranches.isEmpty())
551    {
552      this.excludeBranches = Collections.emptyList();
553    }
554    else
555    {
556      this.excludeBranches = Collections.unmodifiableList(excludeBranches);
557    }
558
559    if ((includeFilters == null) || includeFilters.isEmpty())
560    {
561      this.includeFilters = Collections.emptyList();
562    }
563    else
564    {
565      this.includeFilters = Collections.unmodifiableList(includeFilters);
566    }
567
568    if ((excludeFilters == null) || excludeFilters.isEmpty())
569    {
570      this.excludeFilters = Collections.emptyList();
571    }
572    else
573    {
574      this.excludeFilters = Collections.unmodifiableList(excludeFilters);
575    }
576  }
577
578
579
580  /**
581   * Creates a new re-encode entries task from the provided entry.
582   *
583   * @param  entry  The entry to use to create this re-encode entries task.
584   *
585   * @throws  TaskException  If the provided entry cannot be parsed as a
586   *                         re-encode entries task entry.
587   */
588  public ReEncodeEntriesTask(final Entry entry)
589         throws TaskException
590  {
591    super(entry);
592
593
594    // Get the backend ID.  It must be present.
595    backendID = entry.getAttributeValue(ATTR_BACKEND_ID);
596    if (backendID == null)
597    {
598      throw new TaskException(ERR_REENCODE_TASK_MISSING_REQUIRED_ATTR.get(
599           entry.getDN(), ATTR_BACKEND_ID));
600    }
601
602    // Get the set of include branches.
603    final String[] iBranches = entry.getAttributeValues(ATTR_INCLUDE_BRANCH);
604    if (iBranches == null)
605    {
606      includeBranches = Collections.emptyList();
607    }
608    else
609    {
610      includeBranches = Collections.unmodifiableList(Arrays.asList(iBranches));
611    }
612
613    // Get the set of exclude branches.
614    final String[] eBranches = entry.getAttributeValues(ATTR_EXCLUDE_BRANCH);
615    if (eBranches == null)
616    {
617      excludeBranches = Collections.emptyList();
618    }
619    else
620    {
621      excludeBranches = Collections.unmodifiableList(Arrays.asList(eBranches));
622    }
623
624    // Get the set of include filters.
625    final String[] iFilters = entry.getAttributeValues(ATTR_INCLUDE_FILTER);
626    if (iFilters == null)
627    {
628      includeFilters = Collections.emptyList();
629    }
630    else
631    {
632      includeFilters = Collections.unmodifiableList(Arrays.asList(iFilters));
633    }
634
635    // Get the set of exclude filters.
636    final String[] eFilters = entry.getAttributeValues(ATTR_EXCLUDE_FILTER);
637    if (eFilters == null)
638    {
639      excludeFilters = Collections.emptyList();
640    }
641    else
642    {
643      excludeFilters = Collections.unmodifiableList(Arrays.asList(eFilters));
644    }
645
646    // Get the max entry rate.
647    maxEntriesPerSecond =
648         entry.getAttributeValueAsLong(ATTR_MAX_ENTRIES_PER_SECOND);
649
650    // Determine whether to skip fully uncached entries.
651    final Boolean skipFullyUncached =
652         entry.getAttributeValueAsBoolean(ATTR_SKIP_FULLY_UNCACHED);
653    if (skipFullyUncached == null)
654    {
655      skipFullyUncachedEntries = false;
656    }
657    else
658    {
659      skipFullyUncachedEntries = skipFullyUncached;
660    }
661
662    // Determine whether to skip partially uncached entries.
663    final Boolean skipPartiallyUncached =
664         entry.getAttributeValueAsBoolean(ATTR_SKIP_PARTIALLY_UNCACHED);
665    if (skipPartiallyUncached == null)
666    {
667      skipPartiallyUncachedEntries = false;
668    }
669    else
670    {
671      skipPartiallyUncachedEntries = skipPartiallyUncached;
672    }
673  }
674
675
676
677  /**
678   * Creates a new re-encode entries task from the provided set of task
679   * properties.
680   *
681   * @param  properties  The set of task properties and their corresponding
682   *                     values to use for the task.  It must not be
683   *                     {@code null}.
684   *
685   * @throws  TaskException  If the provided set of properties cannot be used to
686   *                         create a valid re-encode entries task.
687   */
688  public ReEncodeEntriesTask(final Map<TaskProperty,List<Object>> properties)
689         throws TaskException
690  {
691    super(RE_ENCODE_ENTRIES_TASK_CLASS, properties);
692
693    boolean      skipFullyUncached     = false;
694    boolean      skipPartiallyUncached = false;
695    Long         maxRate               = null;
696    List<String> eBranches             = Collections.emptyList();
697    List<String> eFilters              = Collections.emptyList();
698    List<String> iBranches             = Collections.emptyList();
699    List<String> iFilters              = Collections.emptyList();
700    String       id                    = null;
701
702    for (final Map.Entry<TaskProperty,List<Object>> e : properties.entrySet())
703    {
704      final TaskProperty p = e.getKey();
705      final String attrName = p.getAttributeName();
706      final List<Object> values = e.getValue();
707
708      if (attrName.equalsIgnoreCase(ATTR_BACKEND_ID))
709      {
710        id = parseString(p, values, null);
711      }
712      else if (attrName.equalsIgnoreCase(ATTR_INCLUDE_BRANCH))
713      {
714        final String[] branches = parseStrings(p, values, null);
715        if (branches != null)
716        {
717          iBranches = Collections.unmodifiableList(Arrays.asList(branches));
718        }
719      }
720      else if (attrName.equalsIgnoreCase(ATTR_EXCLUDE_BRANCH))
721      {
722        final String[] branches = parseStrings(p, values, null);
723        if (branches != null)
724        {
725          eBranches = Collections.unmodifiableList(Arrays.asList(branches));
726        }
727      }
728      else if (attrName.equalsIgnoreCase(ATTR_INCLUDE_FILTER))
729      {
730        final String[] filters = parseStrings(p, values, null);
731        if (filters != null)
732        {
733          iFilters = Collections.unmodifiableList(Arrays.asList(filters));
734        }
735      }
736      else if (attrName.equalsIgnoreCase(ATTR_EXCLUDE_FILTER))
737      {
738        final String[] filters = parseStrings(p, values, null);
739        if (filters != null)
740        {
741          eFilters = Collections.unmodifiableList(Arrays.asList(filters));
742        }
743      }
744      else if (attrName.equalsIgnoreCase(ATTR_MAX_ENTRIES_PER_SECOND))
745      {
746        maxRate = parseLong(p, values, null);
747      }
748      else if (attrName.equalsIgnoreCase(ATTR_SKIP_FULLY_UNCACHED))
749      {
750        skipFullyUncached = parseBoolean(p, values, false);
751      }
752      else if (attrName.equalsIgnoreCase(ATTR_SKIP_PARTIALLY_UNCACHED))
753      {
754        skipPartiallyUncached = parseBoolean(p, values, false);
755      }
756    }
757
758    if (id == null)
759    {
760      throw new TaskException(ERR_REENCODE_TASK_MISSING_REQUIRED_PROPERTY.get(
761           ATTR_BACKEND_ID));
762    }
763
764    backendID                    = id;
765    includeBranches              = iBranches;
766    excludeBranches              = eBranches;
767    includeFilters               = iFilters;
768    excludeFilters               = eFilters;
769    maxEntriesPerSecond          = maxRate;
770    skipFullyUncachedEntries     = skipFullyUncached;
771    skipPartiallyUncachedEntries = skipPartiallyUncached;
772  }
773
774
775
776  /**
777   * {@inheritDoc}
778   */
779  @Override()
780  public String getTaskName()
781  {
782    return INFO_TASK_NAME_REENCODE_ENTRIES.get();
783  }
784
785
786
787  /**
788   * {@inheritDoc}
789   */
790  @Override()
791  public String getTaskDescription()
792  {
793    return INFO_TASK_DESCRIPTION_REENCODE_ENTRIES.get();
794  }
795
796
797
798  /**
799   * Retrieves the backend ID for the backend containing the entries to
800   * re-encode.
801   *
802   * @return  The backend ID for the backend containing the entries to
803   *          re-encode.
804   */
805  public String getBackendID()
806  {
807    return backendID;
808  }
809
810
811
812  /**
813   * Retrieves the base DNs of the branches to include in re-encode processing,
814   * if defined.
815   *
816   * @return  The base DNs of the branches to include in re-encode processing,
817   *          or an empty list if there should not be any include branches.
818   */
819  public List<String> getIncludeBranches()
820  {
821    return includeBranches;
822  }
823
824
825
826  /**
827   * Retrieves the base DNs of the branches to exclude from re-encode
828   * processing, if defined.
829   *
830   * @return  The base DNs of the branches to exclude from re-encode processing,
831   *          or an empty list if there should not be any exclude branches.
832   */
833  public List<String> getExcludeBranches()
834  {
835    return excludeBranches;
836  }
837
838
839
840  /**
841   * Retrieves a set of filters to use to identify entries to include in
842   * re-encode processing, if defined.
843   *
844   * @return  A set of filters to use to identify entries to include in
845   *          re-encode processing, or an empty list if there should not be any
846   *          include filters.
847   */
848  public List<String> getIncludeFilters()
849  {
850    return includeFilters;
851  }
852
853
854
855  /**
856   * Retrieves a set of filters to use to identify entries to exclude from
857   * re-encode processing, if defined.
858   *
859   * @return  A set of filters to use to identify entries to exclude from
860   *          re-encode processing, or an empty list if there should not be any
861   *          exclude filters.
862   */
863  public List<String> getExcludeFilters()
864  {
865    return excludeFilters;
866  }
867
868
869
870  /**
871   * Retrieves the maximum number of entries that should be re-encoded per
872   * second, if defined.
873   *
874   * @return  The maximum number of entries that should be re-encoded per
875   *          second, or {@code null} if no rate limit should be imposed.
876   */
877  public Long getMaxEntriesPerSecond()
878  {
879    return maxEntriesPerSecond;
880  }
881
882
883
884  /**
885   * Indicates whether to skip re-encode processing for entries that are stored
886   * as fully uncached.
887   *
888   * @return  {@code true} if fully uncached entries should be skipped, or
889   *          {@code false} if not.
890   */
891  public boolean skipFullyUncachedEntries()
892  {
893    return skipFullyUncachedEntries;
894  }
895
896
897
898  /**
899   * Indicates whether to skip re-encode processing for entries that have a
900   * mix of cached and uncached attributes.
901   *
902   * @return  {@code true} if partially uncached entries should be skipped, or
903   *          {@code false} if not.
904   */
905  public boolean skipPartiallyUncachedEntries()
906  {
907    return skipPartiallyUncachedEntries;
908  }
909
910
911
912  /**
913   * {@inheritDoc}
914   */
915  @Override()
916  protected List<String> getAdditionalObjectClasses()
917  {
918    return Collections.singletonList(OC_REENCODE_ENTRIES_TASK);
919  }
920
921
922
923  /**
924   * {@inheritDoc}
925   */
926  @Override()
927  protected List<Attribute> getAdditionalAttributes()
928  {
929    final ArrayList<Attribute> attrList = new ArrayList<>(7);
930    attrList.add(new Attribute(ATTR_BACKEND_ID, backendID));
931    attrList.add(new Attribute(ATTR_SKIP_FULLY_UNCACHED,
932         String.valueOf(skipFullyUncachedEntries)));
933    attrList.add(new Attribute(ATTR_SKIP_PARTIALLY_UNCACHED,
934         String.valueOf(skipPartiallyUncachedEntries)));
935
936    if (! includeBranches.isEmpty())
937    {
938      attrList.add(new Attribute(ATTR_INCLUDE_BRANCH, includeBranches));
939    }
940
941    if (! excludeBranches.isEmpty())
942    {
943      attrList.add(new Attribute(ATTR_EXCLUDE_BRANCH, excludeBranches));
944    }
945
946    if (! includeFilters.isEmpty())
947    {
948      attrList.add(new Attribute(ATTR_INCLUDE_FILTER, includeFilters));
949    }
950
951    if (! excludeFilters.isEmpty())
952    {
953      attrList.add(new Attribute(ATTR_EXCLUDE_FILTER, excludeFilters));
954    }
955
956    if (maxEntriesPerSecond != null)
957    {
958      attrList.add(new Attribute(ATTR_MAX_ENTRIES_PER_SECOND,
959           String.valueOf(maxEntriesPerSecond)));
960    }
961
962    return attrList;
963  }
964
965
966
967  /**
968   * {@inheritDoc}
969   */
970  @Override()
971  public List<TaskProperty> getTaskSpecificProperties()
972  {
973    return Collections.unmodifiableList(Arrays.asList(
974         PROPERTY_BACKEND_ID,
975         PROPERTY_INCLUDE_BRANCH,
976         PROPERTY_EXCLUDE_BRANCH,
977         PROPERTY_INCLUDE_FILTER,
978         PROPERTY_EXCLUDE_FILTER,
979         PROPERTY_MAX_ENTRIES_PER_SECOND,
980         PROPERTY_SKIP_FULLY_UNCACHED,
981         PROPERTY_SKIP_PARTIALLY_UNCACHED));
982  }
983
984
985
986  /**
987   * {@inheritDoc}
988   */
989  @Override()
990  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
991  {
992    final LinkedHashMap<TaskProperty,List<Object>> props =
993         new LinkedHashMap<>(StaticUtils.computeMapCapacity(15));
994
995    props.put(PROPERTY_BACKEND_ID,
996         Collections.<Object>singletonList(backendID));
997    props.put(PROPERTY_INCLUDE_BRANCH,
998         Collections.<Object>unmodifiableList(includeBranches));
999    props.put(PROPERTY_EXCLUDE_BRANCH,
1000         Collections.<Object>unmodifiableList(excludeBranches));
1001    props.put(PROPERTY_INCLUDE_FILTER,
1002         Collections.<Object>unmodifiableList(includeFilters));
1003    props.put(PROPERTY_EXCLUDE_FILTER,
1004         Collections.<Object>unmodifiableList(excludeFilters));
1005
1006    if (maxEntriesPerSecond == null)
1007    {
1008      props.put(PROPERTY_MAX_ENTRIES_PER_SECOND,
1009           Collections.emptyList());
1010    }
1011    else
1012    {
1013      props.put(PROPERTY_MAX_ENTRIES_PER_SECOND,
1014           Collections.<Object>singletonList(maxEntriesPerSecond));
1015    }
1016
1017    props.put(PROPERTY_SKIP_FULLY_UNCACHED,
1018         Collections.<Object>singletonList(skipFullyUncachedEntries));
1019    props.put(PROPERTY_SKIP_PARTIALLY_UNCACHED,
1020         Collections.<Object>singletonList(skipPartiallyUncachedEntries));
1021
1022    props.putAll(super.getTaskPropertyValues());
1023    return Collections.unmodifiableMap(props);
1024  }
1025}