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