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