001/*
002 * Copyright 2008-2022 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2008-2022 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) 2008-2022 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 import LDIF
064 * content into a backend.
065 * <BR>
066 * <BLOCKQUOTE>
067 *   <B>NOTE:</B>  This class, and other classes within the
068 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
069 *   supported for use against Ping Identity, UnboundID, and
070 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
071 *   for proprietary functionality or for external specifications that are not
072 *   considered stable or mature enough to be guaranteed to work in an
073 *   interoperable way with other types of LDAP servers.
074 * </BLOCKQUOTE>
075 * <BR>
076 * The properties that are available for use with this type of task include:
077 * <UL>
078 *   <LI>The paths (on the server system) to the LDIF files containing the data
079 *       to be imported.  At least one LDIF file path must be provided.</LI>
080 *   <LI>The backend ID for the backend into which the data should be
081 *       imported.  It may be omitted only if at least one include branch is
082 *       provided.</LI>
083 *   <LI>A flag that indicates whether to append to the existing data in the
084 *       backend rather than destroying any existing data before beginning the
085 *       import.</LI>
086 *   <LI>A flag that indicates whether to replace entries that already exist
087 *       when operating in append mode.</LI>
088 *   <LI>An optional path (on the server system) to a file to which the server
089 *       should write copies of any entries that are rejected, along with a
090 *       message explaining why they were rejected.</LI>
091 *   <LI>A flag that indicates whether to overwrite the reject file rather than
092 *       append to it if it already exists.</LI>
093 *   <LI>A flag that indicates whether to clear the entire contents of the
094 *       backend even if it has multiple base DNs but only a subset of them
095 *       were provided in the set of include branches.</LI>
096 *   <LI>An optional list of base DNs for branches to include in the
097 *       import.</LI>
098 *   <LI>An optional list of base DNs for branches to exclude from the
099 *       import.</LI>
100 *   <LI>An optional list of search filters that may be used to determine
101 *       whether an entry should be included in the import.</LI>
102 *   <LI>An optional list of search filters that may be used to determine
103 *       whether an entry should be excluded from the import.</LI>
104 *   <LI>An optional list of attributes that should be included in the entries
105 *       that are imported.</LI>
106 *   <LI>An optional list of attributes that should be excluded from the entries
107 *       that are imported.</LI>
108 *   <LI>A flag that indicates whether the LDIF data to import is
109 *       compressed.</LI>
110 *   <LI>A flag that indicates whether the LDIF data to import is
111 *       encrypted.</LI>
112 *   <LI>A flag that indicates whether to skip schema validation for the data
113 *       that is imported.</LI>
114 *   <LI>The path to a file containing a passphrase to use to generate the
115 *       encryption key.</LI>
116 * </UL>
117 */
118@NotMutable()
119@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
120public final class ImportTask
121       extends Task
122{
123  /**
124   * The fully-qualified name of the Java class that is used for the import
125   * task.
126   */
127  @NotNull static final String IMPORT_TASK_CLASS =
128       "com.unboundid.directory.server.tasks.ImportTask";
129
130
131
132  /**
133   * The name of the attribute used to indicate whether to append to an existing
134   * database rather than overwriting its content.
135   */
136  @NotNull private static final String ATTR_APPEND =
137       "ds-task-import-append";
138
139
140
141  /**
142   * The name of the attribute used to specify the backend ID for the backend
143   * into which to import the data.
144   */
145  @NotNull private static final String ATTR_BACKEND_ID =
146       "ds-task-import-backend-id";
147
148
149
150  /**
151   * The name of the attribute used to indicate whether to clear the entire
152   * backend when importing based on base DN.
153   */
154  @NotNull private static final String ATTR_CLEAR_BACKEND =
155       "ds-task-import-clear-backend";
156
157
158
159  /**
160   * The name of the attribute used to specify the path to a file that contains
161   * the passphrase to use to generate the encryption key.
162   */
163  @NotNull private static final String ATTR_ENCRYPTION_PASSPHRASE_FILE =
164       "ds-task-import-encryption-passphrase-file";
165
166
167
168  /**
169   * The name of the attribute used to specify the attributes to exclude from
170   * entries being imported.
171   */
172  @NotNull private static final String ATTR_EXCLUDE_ATTRIBUTE =
173       "ds-task-import-exclude-attribute";
174
175
176
177  /**
178   * The name of the attribute used to specify the base DNs of branches to
179   * exclude from the import.
180   */
181  @NotNull private static final String ATTR_EXCLUDE_BRANCH =
182       "ds-task-import-exclude-branch";
183
184
185
186  /**
187   * The name of the attribute used to specify the filters used to determine
188   * whether to exclude an entry from the import.
189   */
190  @NotNull private static final String ATTR_EXCLUDE_FILTER =
191       "ds-task-import-exclude-filter";
192
193
194
195  /**
196   * The name of the attribute used to specify the attributes to include in
197   * entries being imported.
198   */
199  @NotNull private static final String ATTR_INCLUDE_ATTRIBUTE =
200       "ds-task-import-include-attribute";
201
202
203
204  /**
205   * The name of the attribute used to specify the base DNs of branches to
206   * include in the import.
207   */
208  @NotNull private static final String ATTR_INCLUDE_BRANCH =
209       "ds-task-import-include-branch";
210
211
212
213  /**
214   * The name of the attribute used to specify the filters used to determine
215   * whether to include an entry in the import.
216   */
217  @NotNull private static final String ATTR_INCLUDE_FILTER =
218       "ds-task-import-include-filter";
219
220
221
222  /**
223   * The name of the attribute used to indicate whether the LDIF data is
224   * compressed.
225   */
226  @NotNull private static final String ATTR_IS_COMPRESSED =
227       "ds-task-import-is-compressed";
228
229
230
231  /**
232   * The name of the attribute used to indicate whether the LDIF data is
233   * encrypted.
234   */
235  @NotNull private static final String ATTR_IS_ENCRYPTED =
236       "ds-task-import-is-encrypted";
237
238
239
240  /**
241   * The name of the attribute used to specify the paths to the LDIF files to be
242   * imported.
243   */
244  @NotNull private static final String ATTR_LDIF_FILE =
245       "ds-task-import-ldif-file";
246
247
248
249  /**
250   * The name of the attribute used to indicate whether to overwrite an existing
251   * reject file.
252   */
253  @NotNull private static final String ATTR_OVERWRITE_REJECTS =
254       "ds-task-import-overwrite-rejects";
255
256
257
258  /**
259   * The name of the attribute used to specify the path to the reject file.
260   */
261  @NotNull private static final String ATTR_REJECT_FILE =
262       "ds-task-import-reject-file";
263
264
265
266  /**
267   * The name of the attribute used to indicate whether to replace existing
268   * entries when appending to a database rather than overwriting it.
269   */
270  @NotNull private static final String ATTR_REPLACE_EXISTING =
271       "ds-task-import-replace-existing";
272
273
274
275  /**
276   * The name of the attribute used to indicate whether to skip schema
277   * validation for the import.
278   */
279  @NotNull private static final String ATTR_SKIP_SCHEMA_VALIDATION =
280       "ds-task-import-skip-schema-validation";
281
282
283
284  /**
285   * The name of the attribute used to indicate whether to strip illegal
286   * trailing spaces from LDIF records rather than rejecting those records.
287   */
288  @NotNull private static final String ATTR_STRIP_TRAILING_SPACES =
289       "ds-task-import-strip-trailing-spaces";
290
291
292
293  /**
294   * The task property for the backend ID.
295   */
296  @NotNull private static final TaskProperty PROPERTY_BACKEND_ID =
297       new TaskProperty(ATTR_BACKEND_ID, INFO_DISPLAY_NAME_BACKEND_ID.get(),
298                        INFO_DESCRIPTION_BACKEND_ID_IMPORT.get(), String.class,
299                        false, false, false);
300
301
302
303  /**
304   * The task property for the LDIF files.
305   */
306  @NotNull private static final TaskProperty PROPERTY_LDIF_FILE =
307       new TaskProperty(ATTR_LDIF_FILE, INFO_DISPLAY_NAME_LDIF_FILE.get(),
308                        INFO_DESCRIPTION_LDIF_FILE_IMPORT.get(), String.class,
309                        true, true, false);
310
311
312
313  /**
314   * The task property for the append flag.
315   */
316  @NotNull private static final TaskProperty PROPERTY_APPEND =
317       new TaskProperty(ATTR_APPEND, INFO_DISPLAY_NAME_APPEND_TO_DB.get(),
318                        INFO_DESCRIPTION_APPEND_TO_DB.get(), Boolean.class,
319                        false, false, true);
320
321
322
323  /**
324   * The task property for the replace existing flag.
325   */
326  @NotNull private static final TaskProperty PROPERTY_REPLACE_EXISTING =
327       new TaskProperty(ATTR_REPLACE_EXISTING,
328                        INFO_DISPLAY_NAME_REPLACE_EXISTING.get(),
329                        INFO_DESCRIPTION_REPLACE_EXISTING.get(), Boolean.class,
330                        false, false, true);
331
332
333
334  /**
335   * The task property for the reject file.
336   */
337  @NotNull private static final TaskProperty PROPERTY_REJECT_FILE =
338       new TaskProperty(ATTR_REJECT_FILE,
339                        INFO_DISPLAY_NAME_REJECT_FILE.get(),
340                        INFO_DESCRIPTION_REJECT_FILE.get(), String.class,
341                        false, false, false);
342
343
344
345  /**
346   * The task property for the overwrite rejects flag.
347   */
348  @NotNull private static final TaskProperty PROPERTY_OVERWRITE_REJECTS =
349       new TaskProperty(ATTR_OVERWRITE_REJECTS,
350                        INFO_DISPLAY_NAME_OVERWRITE_REJECTS.get(),
351                        INFO_DESCRIPTION_OVERWRITE_REJECTS.get(), Boolean.class,
352                        false, false, true);
353
354
355
356  /**
357   * The task property for the clear backend flag.
358   */
359  @NotNull private static final TaskProperty PROPERTY_CLEAR_BACKEND =
360       new TaskProperty(ATTR_CLEAR_BACKEND,
361                        INFO_DISPLAY_NAME_CLEAR_BACKEND.get(),
362                        INFO_DESCRIPTION_CLEAR_BACKEND.get(), Boolean.class,
363                        false, false, true);
364
365
366
367  /**
368   * The task property for the include branches.
369   */
370  @NotNull private static final TaskProperty PROPERTY_INCLUDE_BRANCH =
371       new TaskProperty(ATTR_INCLUDE_BRANCH,
372                        INFO_DISPLAY_NAME_INCLUDE_BRANCH.get(),
373                        INFO_DESCRIPTION_INCLUDE_BRANCH_IMPORT.get(),
374                        String.class, false, true, true);
375
376
377
378  /**
379   * The task property for the exclude branches.
380   */
381  @NotNull private static final TaskProperty PROPERTY_EXCLUDE_BRANCH =
382       new TaskProperty(ATTR_EXCLUDE_BRANCH,
383                        INFO_DISPLAY_NAME_EXCLUDE_BRANCH.get(),
384                        INFO_DESCRIPTION_EXCLUDE_BRANCH_IMPORT.get(),
385                        String.class, false, true, true);
386
387
388
389  /**
390   * The task property for the include filters.
391   */
392  @NotNull private static final TaskProperty PROPERTY_INCLUDE_FILTER =
393       new TaskProperty(ATTR_INCLUDE_FILTER,
394                        INFO_DISPLAY_NAME_INCLUDE_FILTER.get(),
395                        INFO_DESCRIPTION_INCLUDE_FILTER_IMPORT.get(),
396                        String.class, false, true, true);
397
398
399
400  /**
401   * The task property for the exclude filters.
402   */
403  @NotNull private static final TaskProperty PROPERTY_EXCLUDE_FILTER =
404       new TaskProperty(ATTR_EXCLUDE_FILTER,
405                        INFO_DISPLAY_NAME_EXCLUDE_FILTER.get(),
406                        INFO_DESCRIPTION_EXCLUDE_FILTER_IMPORT.get(),
407                        String.class, false, true, true);
408
409
410
411  /**
412   * The task property for the include attributes.
413   */
414  @NotNull private static final TaskProperty PROPERTY_INCLUDE_ATTRIBUTE =
415       new TaskProperty(ATTR_INCLUDE_ATTRIBUTE,
416                        INFO_DISPLAY_NAME_INCLUDE_ATTRIBUTE.get(),
417                        INFO_DESCRIPTION_INCLUDE_ATTRIBUTE_IMPORT.get(),
418                        String.class, false, true, true);
419
420
421
422  /**
423   * The task property for the exclude attributes.
424   */
425  @NotNull private static final TaskProperty PROPERTY_EXCLUDE_ATTRIBUTE =
426       new TaskProperty(ATTR_EXCLUDE_ATTRIBUTE,
427                        INFO_DISPLAY_NAME_EXCLUDE_ATTRIBUTE.get(),
428                        INFO_DESCRIPTION_EXCLUDE_ATTRIBUTE_IMPORT.get(),
429                        String.class, false, true, true);
430
431
432
433  /**
434   * The task property for the is compressed flag.
435   */
436  @NotNull private static final TaskProperty PROPERTY_IS_COMPRESSED =
437       new TaskProperty(ATTR_IS_COMPRESSED,
438                        INFO_DISPLAY_NAME_IS_COMPRESSED_IMPORT.get(),
439                        INFO_DESCRIPTION_IS_COMPRESSED_IMPORT.get(),
440                        Boolean.class, false, false, false);
441
442
443
444  /**
445   * The task property for the is encrypted flag.
446   */
447  @NotNull private static final TaskProperty PROPERTY_IS_ENCRYPTED =
448       new TaskProperty(ATTR_IS_ENCRYPTED,
449                        INFO_DISPLAY_NAME_IS_ENCRYPTED_IMPORT.get(),
450                        INFO_DESCRIPTION_IS_ENCRYPTED_IMPORT.get(),
451                        Boolean.class, false, false, false);
452
453
454
455  /**
456   * The task property that will be used for the encryption passphrase file.
457   */
458  @NotNull private static final TaskProperty
459       PROPERTY_ENCRYPTION_PASSPHRASE_FILE = new TaskProperty(
460            ATTR_ENCRYPTION_PASSPHRASE_FILE,
461            INFO_DISPLAY_NAME_ENCRYPTION_PASSPHRASE_FILE.get(),
462            INFO_DESCRIPTION_ENCRYPTION_PASSPHRASE_FILE.get(),
463            String.class, false, false, true);
464
465
466
467  /**
468   * The task property for the skip schema validation flag.
469   */
470  @NotNull private static final TaskProperty PROPERTY_SKIP_SCHEMA_VALIDATION =
471       new TaskProperty(ATTR_SKIP_SCHEMA_VALIDATION,
472                        INFO_DISPLAY_NAME_SKIP_SCHEMA_VALIDATION.get(),
473                        INFO_DESCRIPTION_SKIP_SCHEMA_VALIDATION.get(),
474                        Boolean.class, false, false, false);
475
476
477
478  /**
479   * The task property for the strip trailing spaces flag.
480   */
481  @NotNull private static final TaskProperty PROPERTY_STRIP_TRAILING_SPACES =
482       new TaskProperty(ATTR_STRIP_TRAILING_SPACES,
483                        INFO_DISPLAY_NAME_STRIP_TRAILING_SPACES.get(),
484                        INFO_DESCRIPTION_STRIP_TRAILING_SPACES.get(),
485                        Boolean.class, false, false, false);
486
487
488
489  /**
490   * The name of the object class used in import task entries.
491   */
492  @NotNull private static final String OC_IMPORT_TASK = "ds-task-import";
493
494
495
496  /**
497   * The serial version UID for this serializable class.
498   */
499  private static final long serialVersionUID = 9114913680318281750L;
500
501
502
503  // Indicates whether to append to the database rather than overwriting it.
504  private final boolean append;
505
506  // Indicates whether to clear the entire backend when importing by base DN.
507  private final boolean clearBackend;
508
509  // Indicates whether the LDIF data is compressed.
510  private final boolean isCompressed;
511
512  // Indicates whether the LDIF data is encrypted.
513  private final boolean isEncrypted;
514
515  // Indicates whether to overwrite an existing reject file.
516  private final boolean overwriteRejects;
517
518  // Indicates whether to replace existing entries when appending to the DB.
519  private final boolean replaceExisting;
520
521  // Indicates whether to skip schema validation for the import.
522  private final boolean skipSchemaValidation;
523
524  // Indicates whether to strip illegal trailing spaces from LDIF records rather
525  // than rejecting them.
526  private final boolean stripTrailingSpaces;
527
528  // The set of exclude attributes for the import.
529  @NotNull private final List<String> excludeAttributes;
530
531  // The set of exclude branches for the import.
532  @NotNull private final List<String> excludeBranches;
533
534  // The set of exclude filters for the import.
535  @NotNull private final List<String> excludeFilters;
536
537  // The set of include attributes for the import.
538  @NotNull private final List<String> includeAttributes;
539
540  // The set of include branches for the import.
541  @NotNull private final List<String> includeBranches;
542
543  // The set of include filters for the import.
544  @NotNull private final List<String> includeFilters;
545
546  // The paths to the LDIF files to be imported.
547  @NotNull private final List<String> ldifFiles;
548
549  // The backend ID of the backend to import.
550  @Nullable private final String backendID;
551
552  // The path to a file containing the passphrase to use to generate the
553  // encryption key.
554  @Nullable private final String encryptionPassphraseFile;
555
556  // The path to the reject file to write.
557  @Nullable private final String rejectFile;
558
559
560
561  /**
562   * Creates a new uninitialized import task instance which should only be used
563   * for obtaining general information about this task, including the task name,
564   * description, and supported properties.  Attempts to use a task created with
565   * this constructor for any other reason will likely fail.
566   */
567  public ImportTask()
568  {
569    append = false;
570    clearBackend = false;
571    isCompressed = false;
572    isEncrypted = false;
573    overwriteRejects = false;
574    replaceExisting = false;
575    skipSchemaValidation = false;
576    stripTrailingSpaces = false;
577    encryptionPassphraseFile = null;
578    excludeAttributes = null;
579    excludeBranches = null;
580    excludeFilters = null;
581    includeAttributes = null;
582    includeBranches = null;
583    includeFilters = null;
584    ldifFiles = null;
585    backendID = null;
586    rejectFile = null;
587  }
588
589
590
591  /**
592   * Creates a new import task with the provided backend.  It will overwrite
593   * the contents of the backend with the data in the provided LDIF file.
594   *
595   * @param  taskID     The task ID to use for this task.  If it is {@code null}
596   *                    then a UUID will be generated for use as the task ID.
597   * @param  backendID  The backend ID of the backend into which the data should
598   *                    be imported.  It must not be {@code null}.
599   * @param  ldifFile   The path to the LDIF file containing the data to be
600   *                    imported.  It may be an absolute path or a path relative
601   *                    to the server install root.  It must not be
602   *                    {@code null}.
603   */
604  public ImportTask(@Nullable final String taskID,
605                    @NotNull final String backendID,
606                    @NotNull final String ldifFile)
607  {
608    this(taskID, Collections.singletonList(ldifFile), backendID, false, false,
609         null, false, true, null, null, null, null, null, null, false, false,
610         false, null, null, null, null, null);
611
612    Validator.ensureNotNull(ldifFile);
613  }
614
615
616
617  /**
618   * Creates a new import task with the provided information.
619   *
620   * @param  taskID                  The task ID to use for this task.  If it is
621   *                                 {@code null} then a UUID will be generated
622   *                                 for use as the task ID.
623   * @param  ldifFiles               The paths to the LDIF file containing the
624   *                                 data to be imported.  The paths may be
625   *                                 either absolute or relative to the server
626   *                                 install root.  It must not be {@code null}
627   *                                 or empty.
628   * @param  backendID               The backend ID of the backend into which
629   *                                 the data should be imported.  It may be
630   *                                 {@code null} only if one or more include
631   *                                 branches was specified.
632   * @param  append                  Indicates whether to append to the existing
633   *                                 data rather than overwriting it.
634   * @param  replaceExisting         Indicates whether to replace existing
635   *                                 entries when appending to the database.
636   * @param  rejectFile              The path to a file into which information
637   *                                 will be written about rejected entries.  It
638   *                                 may be {@code null} if no reject file is to
639   *                                 be maintained.
640   * @param  overwriteRejects        Indicates whether to overwrite an existing
641   *                                 rejects file rather than appending to it.
642   * @param  clearBackend            Indicates whether to clear data below all
643   *                                 base DNs in the backend.  It must be
644   *                                 {@code true} if the backend was specified
645   *                                 using a backend ID and no include branches
646   *                                 are specified and {@code append} is
647   *                                 {@code false}.  If include branches were
648   *                                 specified, or if data is being appended to
649   *                                 the backend, then it may be either
650   *                                 {@code true} or {@code false}.
651   * @param  includeBranches         The set of base DNs below which to import
652   *                                 the data.  It may be {@code null} or empty
653   *                                 if a backend ID was specified and data
654   *                                 should be imported below all base DNs
655   *                                 defined in the backend.  Otherwise, at
656   *                                 least one include branch must be provided,
657   *                                 and any data not under one of the include
658   *                                 branches will be excluded from the import.
659   *                                 All include branches must be within the
660   *                                 scope of the same backend.
661   * @param  excludeBranches         The set of base DNs to exclude from the
662   *                                 import.  It may be {@code null} or empty if
663   *                                 no data is to be excluded based on its
664   *                                 location.
665   * @param  includeFilters          The set of filters to use to determine
666   *                                 which entries should be included in the
667   *                                 import.  It may be {@code null} or empty if
668   *                                 no data is to be excluded based on its
669   *                                 content.
670   * @param  excludeFilters          The set of filters to use to determine
671   *                                 which entries should be excluded from the
672   *                                 import.  It may be {@code null} or empty if
673   *                                 no data is to be excluded based on its
674   *                                 content.
675   * @param  includeAttributes       The set of attributes to include in the
676   *                                 entries being imported.  It may be
677   *                                 {@code null} or empty if no attributes
678   *                                 should be excluded from the import.
679   * @param  excludeAttributes       The set of attributes to exclude from the
680   *                                 entries being imported.  It may be
681   *                                 {@code null} or empty if no attributes
682   *                                 should be excluded from the import.
683   * @param  isCompressed            Indicates whether the data in the LDIF
684   *                                 file(s) is compressed.
685   * @param  isEncrypted             Indicates whether the data in the LDIF
686   *                                 file(s) is encrypted.
687   * @param  skipSchemaValidation    Indicates whether to skip schema validation
688   *                                 during the import.
689   * @param  scheduledStartTime      The time that this task should start
690   *                                 running.
691   * @param  dependencyIDs           The list of task IDs that will be required
692   *                                 to complete before this task will be
693   *                                 eligible to start.
694   * @param  failedDependencyAction  Indicates what action should be taken if
695   *                                 any of the dependencies for this task do
696   *                                 not complete successfully.
697   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
698   *                                 that should be notified when this task
699   *                                 completes.
700   * @param  notifyOnError           The list of e-mail addresses of individuals
701   *                                 that should be notified if this task does
702   *                                 not complete successfully.
703   */
704  public ImportTask(@Nullable final String taskID,
705              @NotNull final List<String> ldifFiles,
706              @Nullable final String backendID,
707              final boolean append,
708              final boolean replaceExisting,
709              @Nullable final String rejectFile,
710              final boolean overwriteRejects, final boolean clearBackend,
711              @Nullable final List<String> includeBranches,
712              @Nullable final List<String> excludeBranches,
713              @Nullable final List<String> includeFilters,
714              @Nullable final List<String> excludeFilters,
715              @Nullable final List<String> includeAttributes,
716              @Nullable final List<String> excludeAttributes,
717              final boolean isCompressed, final boolean isEncrypted,
718              final boolean skipSchemaValidation,
719              @Nullable final Date scheduledStartTime,
720              @Nullable final List<String> dependencyIDs,
721              @Nullable final FailedDependencyAction failedDependencyAction,
722              @Nullable final List<String> notifyOnCompletion,
723              @Nullable final List<String> notifyOnError)
724  {
725    this(taskID, ldifFiles, backendID, append, replaceExisting, rejectFile,
726         overwriteRejects, clearBackend, includeBranches, excludeBranches,
727         includeFilters, excludeFilters, includeAttributes, excludeAttributes,
728         isCompressed, isEncrypted, skipSchemaValidation, false,
729         scheduledStartTime, dependencyIDs, failedDependencyAction,
730         notifyOnCompletion, notifyOnError);
731  }
732
733
734
735  /**
736   * Creates a new import task with the provided information.
737   *
738   * @param  taskID                  The task ID to use for this task.  If it is
739   *                                 {@code null} then a UUID will be generated
740   *                                 for use as the task ID.
741   * @param  ldifFiles               The paths to the LDIF file containing the
742   *                                 data to be imported.  The paths may be
743   *                                 either absolute or relative to the server
744   *                                 install root.  It must not be {@code null}
745   *                                 or empty.
746   * @param  backendID               The backend ID of the backend into which
747   *                                 the data should be imported.  It may be
748   *                                 {@code null} only if one or more include
749   *                                 branches was specified.
750   * @param  append                  Indicates whether to append to the existing
751   *                                 data rather than overwriting it.
752   * @param  replaceExisting         Indicates whether to replace existing
753   *                                 entries when appending to the database.
754   * @param  rejectFile              The path to a file into which information
755   *                                 will be written about rejected entries.  It
756   *                                 may be {@code null} if no reject file is to
757   *                                 be maintained.
758   * @param  overwriteRejects        Indicates whether to overwrite an existing
759   *                                 rejects file rather than appending to it.
760   * @param  clearBackend            Indicates whether to clear data below all
761   *                                 base DNs in the backend.  It must be
762   *                                 {@code true} if the backend was specified
763   *                                 using a backend ID and no include branches
764   *                                 are specified and {@code append} is
765   *                                 {@code false}.  If include branches were
766   *                                 specified, or if data is being appended to
767   *                                 the backend, then it may be either
768   *                                 {@code true} or {@code false}.
769   * @param  includeBranches         The set of base DNs below which to import
770   *                                 the data.  It may be {@code null} or empty
771   *                                 if a backend ID was specified and data
772   *                                 should be imported below all base DNs
773   *                                 defined in the backend.  Otherwise, at
774   *                                 least one include branch must be provided,
775   *                                 and any data not under one of the include
776   *                                 branches will be excluded from the import.
777   *                                 All include branches must be within the
778   *                                 scope of the same backend.
779   * @param  excludeBranches         The set of base DNs to exclude from the
780   *                                 import.  It may be {@code null} or empty if
781   *                                 no data is to be excluded based on its
782   *                                 location.
783   * @param  includeFilters          The set of filters to use to determine
784   *                                 which entries should be included in the
785   *                                 import.  It may be {@code null} or empty if
786   *                                 no data is to be excluded based on its
787   *                                 content.
788   * @param  excludeFilters          The set of filters to use to determine
789   *                                 which entries should be excluded from the
790   *                                 import.  It may be {@code null} or empty if
791   *                                 no data is to be excluded based on its
792   *                                 content.
793   * @param  includeAttributes       The set of attributes to include in the
794   *                                 entries being imported.  It may be
795   *                                 {@code null} or empty if no attributes
796   *                                 should be excluded from the import.
797   * @param  excludeAttributes       The set of attributes to exclude from the
798   *                                 entries being imported.  It may be
799   *                                 {@code null} or empty if no attributes
800   *                                 should be excluded from the import.
801   * @param  isCompressed            Indicates whether the data in the LDIF
802   *                                 file(s) is compressed.
803   * @param  isEncrypted             Indicates whether the data in the LDIF
804   *                                 file(s) is encrypted.
805   * @param  skipSchemaValidation    Indicates whether to skip schema validation
806   *                                 during the import.
807   * @param  stripTrailingSpaces     Indicates whether to strip illegal trailing
808   *                                 spaces found in LDIF records rather than
809   *                                 rejecting those records.
810   * @param  scheduledStartTime      The time that this task should start
811   *                                 running.
812   * @param  dependencyIDs           The list of task IDs that will be required
813   *                                 to complete before this task will be
814   *                                 eligible to start.
815   * @param  failedDependencyAction  Indicates what action should be taken if
816   *                                 any of the dependencies for this task do
817   *                                 not complete successfully.
818   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
819   *                                 that should be notified when this task
820   *                                 completes.
821   * @param  notifyOnError           The list of e-mail addresses of individuals
822   *                                 that should be notified if this task does
823   *                                 not complete successfully.
824   */
825  public ImportTask(@Nullable final String taskID,
826              @NotNull final List<String> ldifFiles,
827              @Nullable final String backendID,
828              final boolean append,
829              final boolean replaceExisting,
830              @Nullable final String rejectFile,
831              final boolean overwriteRejects, final boolean clearBackend,
832              @Nullable final List<String> includeBranches,
833              @Nullable final List<String> excludeBranches,
834              @Nullable final List<String> includeFilters,
835              @Nullable final List<String> excludeFilters,
836              @Nullable final List<String> includeAttributes,
837              @Nullable final List<String> excludeAttributes,
838              final boolean isCompressed, final boolean isEncrypted,
839              final boolean skipSchemaValidation,
840              final boolean stripTrailingSpaces,
841              @Nullable final Date scheduledStartTime,
842              @Nullable final List<String> dependencyIDs,
843              @Nullable final FailedDependencyAction failedDependencyAction,
844              @Nullable final List<String> notifyOnCompletion,
845              @Nullable final List<String> notifyOnError)
846  {
847    this(taskID, ldifFiles, backendID, append, replaceExisting, rejectFile,
848         overwriteRejects, clearBackend, includeBranches, excludeBranches,
849         includeFilters, excludeFilters, includeAttributes, excludeAttributes,
850         isCompressed, isEncrypted, null, skipSchemaValidation,
851         stripTrailingSpaces, scheduledStartTime, dependencyIDs,
852         failedDependencyAction, notifyOnCompletion, notifyOnError);
853  }
854
855
856
857  /**
858   * Creates a new import task with the provided information.
859   *
860   * @param  taskID                    The task ID to use for this task.  If it
861   *                                   is {@code null} then a UUID will be
862   *                                   generated for use as the task ID.
863   * @param  ldifFiles                 The paths to the LDIF file containing the
864   *                                   data to be imported.  The paths may be
865   *                                   either absolute or relative to the server
866   *                                   install root.  It must not be
867   *                                   {@code null} or empty.
868   * @param  backendID                 The backend ID of the backend into which
869   *                                   the data should be imported.  It may be
870   *                                   {@code null} only if one or more include
871   *                                   branches was specified.
872   * @param  append                    Indicates whether to append to the
873   *                                   existing data rather than overwriting it.
874   * @param  replaceExisting           Indicates whether to replace existing
875   *                                   entries when appending to the database.
876   * @param  rejectFile                The path to a file into which
877   *                                   information will be written about
878   *                                   rejected entries.  It may be {@code null}
879   *                                   if no reject file is to be maintained.
880   * @param  overwriteRejects          Indicates whether to overwrite an
881   *                                   existing rejects file rather than
882   *                                   appending to it.
883   * @param  clearBackend              Indicates whether to clear data below all
884   *                                   base DNs in the backend.  It must be
885   *                                   {@code true} if the backend was specified
886   *                                   using a backend ID and no include
887   *                                   branches are specified and {@code append}
888   *                                   is {@code false}.  If include branches
889   *                                   were specified, or if data is being
890   *                                   appended to the backend, then it may be
891   *                                   either {@code true} or {@code false}.
892   * @param  includeBranches           The set of base DNs below which to import
893   *                                   the data.  It may be {@code null} or
894   *                                   empty if a backend ID was specified and
895   *                                   data should be imported below all base
896   *                                   DNs defined in the backend.  Otherwise,
897   *                                   at least one include branch must be
898   *                                   provided, and any data not under one of
899   *                                   the include branches will be excluded
900   *                                   from the import.  All include branches
901   *                                   must be within the scope of the same
902   *                                   backend.
903   * @param  excludeBranches           The set of base DNs to exclude from the
904   *                                   import.  It may be {@code null} or empty
905   *                                   if no data is to be excluded based on its
906   *                                   location.
907   * @param  includeFilters            The set of filters to use to determine
908   *                                   which entries should be included in the
909   *                                   import.  It may be {@code null} or empty
910   *                                   if no data is to be excluded based on its
911   *                                   content.
912   * @param  excludeFilters            The set of filters to use to determine
913   *                                   which entries should be excluded from the
914   *                                   import.  It may be {@code null} or empty
915   *                                   if no data is to be excluded based on its
916   *                                   content.
917   * @param  includeAttributes         The set of attributes to include in the
918   *                                   entries being imported.  It may be
919   *                                   {@code null} or empty if no attributes
920   *                                   should be excluded from the import.
921   * @param  excludeAttributes         The set of attributes to exclude from the
922   *                                   entries being imported.  It may be
923   *                                   {@code null} or empty if no attributes
924   *                                   should be excluded from the import.
925   * @param  isCompressed              Indicates whether the data in the LDIF
926   *                                   file(s) is compressed.
927   * @param  isEncrypted               Indicates whether the data in the LDIF
928   *                                   file(s) is encrypted.
929   * @param  encryptionPassphraseFile  The path to a file containing the
930   *                                   passphrase to use to generate the
931   *                                   encryption key.  It amy be {@code null}
932   *                                   if the backup is not to be encrypted, or
933   *                                   if the key should be obtained in some
934   *                                   other way.
935   * @param  skipSchemaValidation      Indicates whether to skip schema
936   *                                   validation during the import.
937   * @param  stripTrailingSpaces       Indicates whether to strip illegal
938   *                                   trailing spaces found in LDIF records
939   *                                   rather than rejecting those records.
940   * @param  scheduledStartTime        The time that this task should start
941   *                                   running.
942   * @param  dependencyIDs             The list of task IDs that will be
943   *                                   required to complete before this task
944   *                                   will be eligible to start.
945   * @param  failedDependencyAction    Indicates what action should be taken if
946   *                                   any of the dependencies for this task do
947   *                                   not complete successfully.
948   * @param  notifyOnCompletion        The list of e-mail addresses of
949   *                                   individuals that should be notified when
950   *                                   this task completes.
951   * @param  notifyOnError             The list of e-mail addresses of
952   *                                   individuals that should be notified if
953   *                                   this task does not complete successfully.
954   */
955  public ImportTask(@Nullable final String taskID,
956              @NotNull final List<String> ldifFiles,
957              @Nullable final String backendID,
958              final boolean append,
959              final boolean replaceExisting,
960              @Nullable final String rejectFile,
961              final boolean overwriteRejects, final boolean clearBackend,
962              @Nullable final List<String> includeBranches,
963              @Nullable final List<String> excludeBranches,
964              @Nullable final List<String> includeFilters,
965              @Nullable final List<String> excludeFilters,
966              @Nullable final List<String> includeAttributes,
967              @Nullable final List<String> excludeAttributes,
968              final boolean isCompressed, final boolean isEncrypted,
969              @Nullable final String encryptionPassphraseFile,
970              final boolean skipSchemaValidation,
971              final boolean stripTrailingSpaces,
972              @Nullable final Date scheduledStartTime,
973              @Nullable final List<String> dependencyIDs,
974              @Nullable final FailedDependencyAction failedDependencyAction,
975              @Nullable final List<String> notifyOnCompletion,
976              @Nullable final List<String> notifyOnError)
977  {
978    this(taskID, ldifFiles, backendID, append, replaceExisting, rejectFile,
979         overwriteRejects, clearBackend, includeBranches, excludeBranches,
980         includeFilters, excludeFilters, includeAttributes,
981         excludeAttributes, isCompressed, isEncrypted,
982         encryptionPassphraseFile, skipSchemaValidation, stripTrailingSpaces,
983         scheduledStartTime, dependencyIDs, failedDependencyAction, null,
984         notifyOnCompletion, null, notifyOnError, null, null, null);
985  }
986
987
988
989  /**
990   * Creates a new import task with the provided information.
991   *
992   * @param  taskID                    The task ID to use for this task.  If it
993   *                                   is {@code null} then a UUID will be
994   *                                   generated for use as the task ID.
995   * @param  ldifFiles                 The paths to the LDIF file containing the
996   *                                   data to be imported.  The paths may be
997   *                                   either absolute or relative to the server
998   *                                   install root.  It must not be
999   *                                   {@code null} or empty.
1000   * @param  backendID                 The backend ID of the backend into which
1001   *                                   the data should be imported.  It may be
1002   *                                   {@code null} only if one or more include
1003   *                                   branches was specified.
1004   * @param  append                    Indicates whether to append to the
1005   *                                   existing data rather than overwriting it.
1006   * @param  replaceExisting           Indicates whether to replace existing
1007   *                                   entries when appending to the database.
1008   * @param  rejectFile                The path to a file into which
1009   *                                   information will be written about
1010   *                                   rejected entries.  It may be {@code null}
1011   *                                   if no reject file is to be maintained.
1012   * @param  overwriteRejects          Indicates whether to overwrite an
1013   *                                   existing rejects file rather than
1014   *                                   appending to it.
1015   * @param  clearBackend              Indicates whether to clear data below all
1016   *                                   base DNs in the backend.  It must be
1017   *                                   {@code true} if the backend was specified
1018   *                                   using a backend ID and no include
1019   *                                   branches are specified and {@code append}
1020   *                                   is {@code false}.  If include branches
1021   *                                   were specified, or if data is being
1022   *                                   appended to the backend, then it may be
1023   *                                   either {@code true} or {@code false}.
1024   * @param  includeBranches           The set of base DNs below which to import
1025   *                                   the data.  It may be {@code null} or
1026   *                                   empty if a backend ID was specified and
1027   *                                   data should be imported below all base
1028   *                                   DNs defined in the backend.  Otherwise,
1029   *                                   at least one include branch must be
1030   *                                   provided, and any data not under one of
1031   *                                   the include branches will be excluded
1032   *                                   from the import.  All include branches
1033   *                                   must be within the scope of the same
1034   *                                   backend.
1035   * @param  excludeBranches           The set of base DNs to exclude from the
1036   *                                   import.  It may be {@code null} or empty
1037   *                                   if no data is to be excluded based on its
1038   *                                   location.
1039   * @param  includeFilters            The set of filters to use to determine
1040   *                                   which entries should be included in the
1041   *                                   import.  It may be {@code null} or empty
1042   *                                   if no data is to be excluded based on its
1043   *                                   content.
1044   * @param  excludeFilters            The set of filters to use to determine
1045   *                                   which entries should be excluded from the
1046   *                                   import.  It may be {@code null} or empty
1047   *                                   if no data is to be excluded based on its
1048   *                                   content.
1049   * @param  includeAttributes         The set of attributes to include in the
1050   *                                   entries being imported.  It may be
1051   *                                   {@code null} or empty if no attributes
1052   *                                   should be excluded from the import.
1053   * @param  excludeAttributes         The set of attributes to exclude from the
1054   *                                   entries being imported.  It may be
1055   *                                   {@code null} or empty if no attributes
1056   *                                   should be excluded from the import.
1057   * @param  isCompressed              Indicates whether the data in the LDIF
1058   *                                   file(s) is compressed.
1059   * @param  isEncrypted               Indicates whether the data in the LDIF
1060   *                                   file(s) is encrypted.
1061   * @param  encryptionPassphraseFile  The path to a file containing the
1062   *                                   passphrase to use to generate the
1063   *                                   encryption key.  It amy be {@code null}
1064   *                                   if the backup is not to be encrypted, or
1065   *                                   if the key should be obtained in some
1066   *                                   other way.
1067   * @param  skipSchemaValidation      Indicates whether to skip schema
1068   *                                   validation during the import.
1069   * @param  stripTrailingSpaces       Indicates whether to strip illegal
1070   *                                   trailing spaces found in LDIF records
1071   *                                   rather than rejecting those records.
1072   * @param  scheduledStartTime        The time that this task should start
1073   *                                   running.
1074   * @param  dependencyIDs             The list of task IDs that will be
1075   *                                   required to complete before this task
1076   *                                   will be eligible to start.
1077   * @param  failedDependencyAction    Indicates what action should be taken if
1078   *                                   any of the dependencies for this task do
1079   *                                   not complete successfully.
1080   * @param  notifyOnStart             The list of e-mail addresses of
1081   *                                   individuals that should be notified when
1082   *                                   this task starts running.
1083   * @param  notifyOnCompletion        The list of e-mail addresses of
1084   *                                   individuals that should be notified when
1085   *                                   this task completes.
1086   * @param  notifyOnSuccess           The list of e-mail addresses of
1087   *                                   individuals that should be notified if
1088   *                                   this task completes successfully.
1089   * @param  notifyOnError             The list of e-mail addresses of
1090   *                                   individuals that should be notified if
1091   *                                   this task does not complete successfully.
1092   * @param  alertOnStart              Indicates whether the server should send
1093   *                                   an alert notification when this task
1094   *                                   starts.
1095   * @param  alertOnSuccess            Indicates whether the server should send
1096   *                                   an alert notification if this task
1097   *                                   completes successfully.
1098   * @param  alertOnError              Indicates whether the server should send
1099   *                                   an alert notification if this task fails
1100   *                                   to complete successfully.
1101   */
1102  public ImportTask(@Nullable final String taskID,
1103              @NotNull final List<String> ldifFiles,
1104              @Nullable final String backendID, final boolean append,
1105              final boolean replaceExisting,
1106              @Nullable final String rejectFile,
1107              final boolean overwriteRejects, final boolean clearBackend,
1108              @Nullable final List<String> includeBranches,
1109              @Nullable final List<String> excludeBranches,
1110              @Nullable final List<String> includeFilters,
1111              @Nullable final List<String> excludeFilters,
1112              @Nullable final List<String> includeAttributes,
1113              @Nullable final List<String> excludeAttributes,
1114              final boolean isCompressed, final boolean isEncrypted,
1115              @Nullable final String encryptionPassphraseFile,
1116              final boolean skipSchemaValidation,
1117              final boolean stripTrailingSpaces,
1118              @Nullable final Date scheduledStartTime,
1119              @Nullable final List<String> dependencyIDs,
1120              @Nullable final FailedDependencyAction failedDependencyAction,
1121              @Nullable final List<String> notifyOnStart,
1122              @Nullable final List<String> notifyOnCompletion,
1123              @Nullable final List<String> notifyOnSuccess,
1124              @Nullable final List<String> notifyOnError,
1125              @Nullable final Boolean alertOnStart,
1126              @Nullable final Boolean alertOnSuccess,
1127              @Nullable final Boolean alertOnError)
1128  {
1129    super(taskID, IMPORT_TASK_CLASS, scheduledStartTime,
1130         dependencyIDs, failedDependencyAction, notifyOnStart,
1131         notifyOnCompletion, notifyOnSuccess, notifyOnError, alertOnStart,
1132         alertOnSuccess, alertOnError);
1133
1134    Validator.ensureNotNull(ldifFiles);
1135    Validator.ensureFalse(ldifFiles.isEmpty(),
1136         "ImportTask.ldifFiles must not be empty.");
1137    Validator.ensureFalse((backendID == null) &&
1138         ((includeBranches == null) || includeBranches.isEmpty()));
1139    Validator.ensureTrue(clearBackend || append ||
1140         ((includeBranches != null) && (! includeBranches.isEmpty())));
1141
1142    this.ldifFiles = Collections.unmodifiableList(ldifFiles);
1143    this.backendID = backendID;
1144    this.append = append;
1145    this.replaceExisting = replaceExisting;
1146    this.rejectFile = rejectFile;
1147    this.overwriteRejects = overwriteRejects;
1148    this.clearBackend = clearBackend;
1149    this.isCompressed = isCompressed;
1150    this.isEncrypted = isEncrypted;
1151    this.encryptionPassphraseFile = encryptionPassphraseFile;
1152    this.skipSchemaValidation = skipSchemaValidation;
1153    this.stripTrailingSpaces = stripTrailingSpaces;
1154
1155    if (includeBranches == null)
1156    {
1157      this.includeBranches = Collections.emptyList();
1158    }
1159    else
1160    {
1161      this.includeBranches = Collections.unmodifiableList(includeBranches);
1162    }
1163
1164    if (excludeBranches == null)
1165    {
1166      this.excludeBranches = Collections.emptyList();
1167    }
1168    else
1169    {
1170      this.excludeBranches = Collections.unmodifiableList(excludeBranches);
1171    }
1172
1173    if (includeFilters == null)
1174    {
1175      this.includeFilters = Collections.emptyList();
1176    }
1177    else
1178    {
1179      this.includeFilters = Collections.unmodifiableList(includeFilters);
1180    }
1181
1182    if (excludeFilters == null)
1183    {
1184      this.excludeFilters = Collections.emptyList();
1185    }
1186    else
1187    {
1188      this.excludeFilters = Collections.unmodifiableList(excludeFilters);
1189    }
1190
1191    if (includeAttributes == null)
1192    {
1193      this.includeAttributes = Collections.emptyList();
1194    }
1195    else
1196    {
1197      this.includeAttributes = Collections.unmodifiableList(includeAttributes);
1198    }
1199
1200    if (excludeAttributes == null)
1201    {
1202      this.excludeAttributes = Collections.emptyList();
1203    }
1204    else
1205    {
1206      this.excludeAttributes = Collections.unmodifiableList(excludeAttributes);
1207    }
1208  }
1209
1210
1211
1212  /**
1213   * Creates a new import task from the provided entry.
1214   *
1215   * @param  entry  The entry to use to create this import task.
1216   *
1217   * @throws  TaskException  If the provided entry cannot be parsed as an import
1218   *                         task entry.
1219   */
1220  public ImportTask(@NotNull final Entry entry)
1221         throws TaskException
1222  {
1223    super(entry);
1224
1225
1226    // Get the set of LDIF files.  It must be present.
1227    final String[] files = entry.getAttributeValues(ATTR_LDIF_FILE);
1228    if ((files == null) || (files.length == 0))
1229    {
1230      throw new TaskException(ERR_IMPORT_TASK_NO_LDIF.get(getTaskEntryDN()));
1231    }
1232    else
1233    {
1234      ldifFiles = Collections.unmodifiableList(Arrays.asList(files));
1235    }
1236
1237
1238    // Get the backend ID.  It may be absent.
1239    backendID = entry.getAttributeValue(ATTR_BACKEND_ID);
1240
1241
1242    // Get the append flag.  It may be absent.
1243    append = parseBooleanValue(entry, ATTR_APPEND, false);
1244
1245
1246    // Get the replaceExisting flag.  It may be absent.
1247    replaceExisting = parseBooleanValue(entry, ATTR_REPLACE_EXISTING, false);
1248
1249
1250    // Get the reject file.  It may be absent.
1251    rejectFile = entry.getAttributeValue(ATTR_REJECT_FILE);
1252
1253
1254    // Get the overwriteRejects flag.  It may be absent.
1255    overwriteRejects = parseBooleanValue(entry, ATTR_OVERWRITE_REJECTS, false);
1256
1257
1258    // Get the clearBackend flag.  It may be absent.
1259    clearBackend = parseBooleanValue(entry, ATTR_CLEAR_BACKEND, false);
1260
1261
1262    // Get the list of include branches.  It may be absent.
1263    includeBranches = parseStringList(entry, ATTR_INCLUDE_BRANCH);
1264
1265
1266    // Get the list of exclude branches.  It may be absent.
1267    excludeBranches = parseStringList(entry, ATTR_EXCLUDE_BRANCH);
1268
1269
1270    // Get the list of include filters.  It may be absent.
1271    includeFilters = parseStringList(entry, ATTR_INCLUDE_FILTER);
1272
1273
1274    // Get the list of exclude filters.  It may be absent.
1275    excludeFilters = parseStringList(entry, ATTR_EXCLUDE_FILTER);
1276
1277
1278    // Get the list of include attributes.  It may be absent.
1279    includeAttributes = parseStringList(entry, ATTR_INCLUDE_ATTRIBUTE);
1280
1281
1282    // Get the list of exclude attributes.  It may be absent.
1283    excludeAttributes = parseStringList(entry, ATTR_EXCLUDE_ATTRIBUTE);
1284
1285
1286    // Get the isCompressed flag.  It may be absent.
1287    isCompressed = parseBooleanValue(entry, ATTR_IS_COMPRESSED, false);
1288
1289
1290    // Get the isEncrypted flag.  It may be absent.
1291    isEncrypted = parseBooleanValue(entry, ATTR_IS_ENCRYPTED, false);
1292
1293
1294    // Get the path to the encryption passphrase file.  It may be absent.
1295    encryptionPassphraseFile =
1296         entry.getAttributeValue(ATTR_ENCRYPTION_PASSPHRASE_FILE);
1297
1298
1299    // Get the skipSchemaValidation flag.  It may be absent.
1300    skipSchemaValidation = parseBooleanValue(entry, ATTR_SKIP_SCHEMA_VALIDATION,
1301                                             false);
1302
1303
1304    // Get the stripTrailingSpaces flag.  It may be absent.
1305    stripTrailingSpaces = parseBooleanValue(entry, ATTR_STRIP_TRAILING_SPACES,
1306                                            false);
1307  }
1308
1309
1310
1311  /**
1312   * Creates a new import task from the provided set of task properties.
1313   *
1314   * @param  properties  The set of task properties and their corresponding
1315   *                     values to use for the task.  It must not be
1316   *                     {@code null}.
1317   *
1318   * @throws  TaskException  If the provided set of properties cannot be used to
1319   *                         create a valid import task.
1320   */
1321  public ImportTask(@NotNull final Map<TaskProperty,List<Object>> properties)
1322         throws TaskException
1323  {
1324    super(IMPORT_TASK_CLASS, properties);
1325
1326    boolean  a  = false;
1327    boolean  c  = false;
1328    boolean  cB = true;
1329    boolean  e  = false;
1330    boolean  o  = false;
1331    boolean  r  = false;
1332    boolean  ss = false;
1333    boolean  st = false;
1334    String   b  = null;
1335    String   pF = null;
1336    String   rF = null;
1337    String[] eA = StaticUtils.NO_STRINGS;
1338    String[] eB = StaticUtils.NO_STRINGS;
1339    String[] eF = StaticUtils.NO_STRINGS;
1340    String[] iA = StaticUtils.NO_STRINGS;
1341    String[] iB = StaticUtils.NO_STRINGS;
1342    String[] iF = StaticUtils.NO_STRINGS;
1343    String[] l  = StaticUtils.NO_STRINGS;
1344
1345    for (final Map.Entry<TaskProperty,List<Object>> entry :
1346         properties.entrySet())
1347    {
1348      final TaskProperty p = entry.getKey();
1349      final String attrName = p.getAttributeName();
1350      final List<Object> values = entry.getValue();
1351
1352      if (attrName.equalsIgnoreCase(ATTR_BACKEND_ID))
1353      {
1354        b = parseString(p, values, b);
1355      }
1356      else if (attrName.equalsIgnoreCase(ATTR_LDIF_FILE))
1357      {
1358        l = parseStrings(p, values, l);
1359      }
1360      else if (attrName.equalsIgnoreCase(ATTR_APPEND))
1361      {
1362        a = parseBoolean(p, values, a);
1363      }
1364      else if (attrName.equalsIgnoreCase(ATTR_REPLACE_EXISTING))
1365      {
1366        r = parseBoolean(p, values, r);
1367      }
1368      else if (attrName.equalsIgnoreCase(ATTR_REJECT_FILE))
1369      {
1370        rF = parseString(p, values, rF);
1371      }
1372      else if (attrName.equalsIgnoreCase(ATTR_OVERWRITE_REJECTS))
1373      {
1374        o = parseBoolean(p, values, o);
1375      }
1376      else if (attrName.equalsIgnoreCase(ATTR_CLEAR_BACKEND))
1377      {
1378        cB = parseBoolean(p, values, cB);
1379      }
1380      else if (attrName.equalsIgnoreCase(ATTR_INCLUDE_BRANCH))
1381      {
1382        iB = parseStrings(p, values, iB);
1383      }
1384      else if (attrName.equalsIgnoreCase(ATTR_EXCLUDE_BRANCH))
1385      {
1386        eB = parseStrings(p, values, eB);
1387      }
1388      else if (attrName.equalsIgnoreCase(ATTR_INCLUDE_FILTER))
1389      {
1390        iF = parseStrings(p, values, iF);
1391      }
1392      else if (attrName.equalsIgnoreCase(ATTR_EXCLUDE_FILTER))
1393      {
1394        eF = parseStrings(p, values, eF);
1395      }
1396      else if (attrName.equalsIgnoreCase(ATTR_INCLUDE_ATTRIBUTE))
1397      {
1398        iA = parseStrings(p, values, iA);
1399      }
1400      else if (attrName.equalsIgnoreCase(ATTR_EXCLUDE_ATTRIBUTE))
1401      {
1402        eA = parseStrings(p, values, eA);
1403      }
1404      else if (attrName.equalsIgnoreCase(ATTR_IS_COMPRESSED))
1405      {
1406        c = parseBoolean(p, values, c);
1407      }
1408      else if (attrName.equalsIgnoreCase(ATTR_IS_ENCRYPTED))
1409      {
1410        e = parseBoolean(p, values, e);
1411      }
1412      else if (attrName.equalsIgnoreCase(ATTR_ENCRYPTION_PASSPHRASE_FILE))
1413      {
1414        pF = parseString(p, values, pF);
1415      }
1416      else if (attrName.equalsIgnoreCase(ATTR_SKIP_SCHEMA_VALIDATION))
1417      {
1418        ss = parseBoolean(p, values, ss);
1419      }
1420      else if (attrName.equalsIgnoreCase(ATTR_STRIP_TRAILING_SPACES))
1421      {
1422        st = parseBoolean(p, values, st);
1423      }
1424    }
1425
1426    if ((b == null) && (iB.length == 0))
1427    {
1428      throw new TaskException(
1429                     ERR_IMPORT_TASK_NO_BACKEND_ID_OR_INCLUDE_BRANCHES.get(
1430                          getTaskEntryDN()));
1431    }
1432
1433    if (l == null)
1434    {
1435      throw new TaskException(ERR_IMPORT_TASK_NO_LDIF.get(
1436                                   getTaskEntryDN()));
1437    }
1438
1439    backendID = b;
1440    ldifFiles = Collections.unmodifiableList(Arrays.asList(l));
1441    append = a;
1442    replaceExisting = r;
1443    rejectFile = rF;
1444    overwriteRejects = o;
1445    clearBackend = cB;
1446    includeAttributes = Collections.unmodifiableList(Arrays.asList(iA));
1447    excludeAttributes = Collections.unmodifiableList(Arrays.asList(eA));
1448    includeBranches = Collections.unmodifiableList(Arrays.asList(iB));
1449    excludeBranches = Collections.unmodifiableList(Arrays.asList(eB));
1450    includeFilters = Collections.unmodifiableList(Arrays.asList(iF));
1451    excludeFilters = Collections.unmodifiableList(Arrays.asList(eF));
1452    isCompressed = c;
1453    isEncrypted = e;
1454    encryptionPassphraseFile = pF;
1455    skipSchemaValidation = ss;
1456    stripTrailingSpaces = st;
1457  }
1458
1459
1460
1461  /**
1462   * {@inheritDoc}
1463   */
1464  @Override()
1465  @NotNull()
1466  public String getTaskName()
1467  {
1468    return INFO_TASK_NAME_IMPORT.get();
1469  }
1470
1471
1472
1473  /**
1474   * {@inheritDoc}
1475   */
1476  @Override()
1477  @NotNull()
1478  public String getTaskDescription()
1479  {
1480    return INFO_TASK_DESCRIPTION_IMPORT.get();
1481  }
1482
1483
1484
1485  /**
1486   * Retrieves the paths to the LDIF files containing the data to be imported.
1487   * The paths may be absolute or relative to the server root.
1488   *
1489   * @return  The paths to the LDIF files containing the data to be imported.
1490   */
1491  @NotNull()
1492  public List<String> getLDIFFiles()
1493  {
1494    return ldifFiles;
1495  }
1496
1497
1498
1499  /**
1500   * Retrieves the backend ID of the backend into which the data should be
1501   * imported.
1502   *
1503   * @return  The backend ID of the backend into which the data should be
1504   *          imported, or {@code null} if no backend ID was specified and the
1505   *          backend will be identified from the include branches.
1506   */
1507  @Nullable()
1508  public String getBackendID()
1509  {
1510    return backendID;
1511  }
1512
1513
1514
1515  /**
1516   * Indicates whether the import should append to the data in the backend
1517   * rather than clearing the backend before performing the import.
1518   *
1519   * @return  {@code true} if the contents of the existing backend should be
1520   *          retained and the new data appended to it, or {@code false} if the
1521   *          existing content should be cleared prior to performing the import.
1522   */
1523  public boolean append()
1524  {
1525    return append;
1526  }
1527
1528
1529
1530  /**
1531   * Indicates whether to replace existing entries when appending data to the
1532   * backend.  This is only applicable if {@code append()} returns {@code true}.
1533   *
1534   * @return  {@code true} if entries already present in the backend should be
1535   *          replaced if that entry is also present in the LDIF file, or
1536   *          {@code false} if entries already present in the backend should be
1537   *          retained and the corresponding entry contained in the LDIF should
1538   *          be skipped.
1539   */
1540  public boolean replaceExistingEntries()
1541  {
1542    return replaceExisting;
1543  }
1544
1545
1546
1547  /**
1548   * Retrieves the path to a file to which rejected entries should be written.
1549   *
1550   * @return  The path to a file to which rejected entries should be written, or
1551   *          {@code null} if a rejected entries file should not be maintained.
1552   */
1553  @Nullable()
1554  public String getRejectFile()
1555  {
1556    return rejectFile;
1557  }
1558
1559
1560
1561  /**
1562   * Indicates whether an existing reject file should be overwritten rather than
1563   * appending to it.
1564   *
1565   * @return  {@code true} if an existing reject file should be overwritten, or
1566   *          {@code false} if the server should append to it.
1567   */
1568  public boolean overwriteRejectFile()
1569  {
1570    return overwriteRejects;
1571  }
1572
1573
1574
1575  /**
1576   * Indicates whether data below all base DNs defined in the backend should be
1577   * cleared before performing the import.  This is not applicable if the import
1578   * is to append to the backend, or if the backend only has a single base DN.
1579   *
1580   * @return  {@code true} if data below all base DNs in the backend should be
1581   *          cleared, or {@code false} if only data below the base DNs that
1582   *          correspond to the configured include branches should be cleared.
1583   */
1584  public boolean clearBackend()
1585  {
1586    return clearBackend;
1587  }
1588
1589
1590
1591  /**
1592   * Retrieves the list of base DNs for branches that should be included in the
1593   * import.
1594   *
1595   * @return  The set of base DNs for branches that should be included in the
1596   *          import, or an empty list if data should be imported from all base
1597   *          DNs in the associated backend.
1598   */
1599  @NotNull()
1600  public List<String> getIncludeBranches()
1601  {
1602    return includeBranches;
1603  }
1604
1605
1606
1607  /**
1608   * Retrieves the list of base DNs of branches that should be excluded from the
1609   * import.
1610   *
1611   * @return  The list of base DNs of branches that should be excluded from the
1612   *          import, or an empty list if no entries should be excluded from the
1613   *          import based on their location.
1614   */
1615  @NotNull()
1616  public List<String> getExcludeBranches()
1617  {
1618    return excludeBranches;
1619  }
1620
1621
1622
1623  /**
1624   * Retrieves the list of search filters that may be used to identify which
1625   * entries should be included in the import.
1626   *
1627   * @return  The list of search filters that may be used to identify which
1628   *          entries should be included in the import, or an empty list if no
1629   *          entries should be excluded from the import based on their content.
1630   */
1631  @NotNull()
1632  public List<String> getIncludeFilters()
1633  {
1634    return includeFilters;
1635  }
1636
1637
1638
1639  /**
1640   * Retrieves the list of search filters that may be used to identify which
1641   * entries should be excluded from the import.
1642   *
1643   * @return  The list of search filters that may be used to identify which
1644   *          entries should be excluded from the import, or an empty list if no
1645   *          entries should be excluded from the import based on their content.
1646   */
1647  @NotNull()
1648  public List<String> getExcludeFilters()
1649  {
1650    return excludeFilters;
1651  }
1652
1653
1654
1655  /**
1656   * Retrieves the list of attributes that should be included in the imported
1657   * entries.
1658   *
1659   * @return  The list of attributes that should be included in the imported
1660   *          entries, or an empty list if no attributes should be excluded.
1661   */
1662  @NotNull()
1663  public List<String> getIncludeAttributes()
1664  {
1665    return includeAttributes;
1666  }
1667
1668
1669
1670  /**
1671   * Retrieves the list of attributes that should be excluded from the imported
1672   * entries.
1673   *
1674   * @return  The list of attributes that should be excluded from the imported
1675   *          entries, or an empty list if no attributes should be excluded.
1676   */
1677  @NotNull()
1678  public List<String> getExcludeAttributes()
1679  {
1680    return excludeAttributes;
1681  }
1682
1683
1684
1685  /**
1686   * Indicates whether the LDIF data to import is compressed.
1687   *
1688   * @return  {@code true} if the LDIF data to import is compressed, or
1689   *          {@code false} if not.
1690   */
1691  public boolean isCompressed()
1692  {
1693    return isCompressed;
1694  }
1695
1696
1697
1698  /**
1699   * Indicates whether the LDIF data to import is encrypted.
1700   *
1701   * @return  {@code true} if the LDIF data to import is encrypted, or
1702   *          {@code false} if not.
1703   */
1704  public boolean isEncrypted()
1705  {
1706    return isEncrypted;
1707  }
1708
1709
1710
1711  /**
1712   * Retrieves the path to a file that contains the passphrase to use to
1713   * generate the encryption key.
1714   *
1715   * @return  The path to a file that contains the passphrase to use to
1716   *          generate the encryption key, or {@code null} if the LDIF file is
1717   *          not encrypted or if the encryption key should be obtained through
1718   *          some other means.
1719   */
1720  @NotNull()
1721  public String getEncryptionPassphraseFile()
1722  {
1723    return encryptionPassphraseFile;
1724  }
1725
1726
1727
1728  /**
1729   * Indicates whether the server should skip schema validation processing when
1730   * performing the import.
1731   *
1732   * @return  {@code true} if the server should skip schema validation
1733   *          processing when performing the import, or {@code false} if not.
1734   */
1735  public boolean skipSchemaValidation()
1736  {
1737    return skipSchemaValidation;
1738  }
1739
1740
1741
1742  /**
1743   * Indicates whether the server should strip off any illegal trailing spaces
1744   * found in LDIF records rather than rejecting those records.
1745   *
1746   * @return  {@code true} if the server should strip off any illegal trailing
1747   *          spaces found in LDIF records, or {@code false} if it should reject
1748   *          any records containing illegal trailing spaces.
1749   */
1750  public boolean stripTrailingSpaces()
1751  {
1752    return stripTrailingSpaces;
1753  }
1754
1755
1756
1757  /**
1758   * {@inheritDoc}
1759   */
1760  @Override()
1761  @NotNull()
1762  protected List<String> getAdditionalObjectClasses()
1763  {
1764    return Collections.singletonList(OC_IMPORT_TASK);
1765  }
1766
1767
1768
1769  /**
1770   * {@inheritDoc}
1771   */
1772  @Override()
1773  @NotNull()
1774  protected List<Attribute> getAdditionalAttributes()
1775  {
1776    final ArrayList<Attribute> attrs = new ArrayList<>(20);
1777
1778    attrs.add(new Attribute(ATTR_LDIF_FILE, ldifFiles));
1779    attrs.add(new Attribute(ATTR_APPEND, String.valueOf(append)));
1780    attrs.add(new Attribute(ATTR_REPLACE_EXISTING,
1781                            String.valueOf(replaceExisting)));
1782    attrs.add(new Attribute(ATTR_OVERWRITE_REJECTS,
1783                            String.valueOf(overwriteRejects)));
1784    attrs.add(new Attribute(ATTR_CLEAR_BACKEND, String.valueOf(clearBackend)));
1785    attrs.add(new Attribute(ATTR_IS_COMPRESSED, String.valueOf(isCompressed)));
1786    attrs.add(new Attribute(ATTR_IS_ENCRYPTED, String.valueOf(isEncrypted)));
1787    attrs.add(new Attribute(ATTR_SKIP_SCHEMA_VALIDATION,
1788                            String.valueOf(skipSchemaValidation)));
1789
1790    if (stripTrailingSpaces)
1791    {
1792      attrs.add(new Attribute(ATTR_STRIP_TRAILING_SPACES,
1793           String.valueOf(stripTrailingSpaces)));
1794    }
1795
1796    if (backendID != null)
1797    {
1798      attrs.add(new Attribute(ATTR_BACKEND_ID, backendID));
1799    }
1800
1801    if (rejectFile != null)
1802    {
1803      attrs.add(new Attribute(ATTR_REJECT_FILE, rejectFile));
1804    }
1805
1806    if (! includeBranches.isEmpty())
1807    {
1808      attrs.add(new Attribute(ATTR_INCLUDE_BRANCH, includeBranches));
1809    }
1810
1811    if (! excludeBranches.isEmpty())
1812    {
1813      attrs.add(new Attribute(ATTR_EXCLUDE_BRANCH, excludeBranches));
1814    }
1815
1816    if (! includeAttributes.isEmpty())
1817    {
1818      attrs.add(new Attribute(ATTR_INCLUDE_ATTRIBUTE, includeAttributes));
1819    }
1820
1821    if (! excludeAttributes.isEmpty())
1822    {
1823      attrs.add(new Attribute(ATTR_EXCLUDE_ATTRIBUTE, excludeAttributes));
1824    }
1825
1826    if (! includeFilters.isEmpty())
1827    {
1828      attrs.add(new Attribute(ATTR_INCLUDE_FILTER, includeFilters));
1829    }
1830
1831    if (! excludeFilters.isEmpty())
1832    {
1833      attrs.add(new Attribute(ATTR_EXCLUDE_FILTER, excludeFilters));
1834    }
1835
1836    if (encryptionPassphraseFile != null)
1837    {
1838      attrs.add(new Attribute(ATTR_ENCRYPTION_PASSPHRASE_FILE,
1839           encryptionPassphraseFile));
1840    }
1841
1842    return attrs;
1843  }
1844
1845
1846
1847  /**
1848   * {@inheritDoc}
1849   */
1850  @Override()
1851  @NotNull()
1852  public List<TaskProperty> getTaskSpecificProperties()
1853  {
1854    final List<TaskProperty> propList = Arrays.asList(
1855         PROPERTY_BACKEND_ID,
1856         PROPERTY_LDIF_FILE,
1857         PROPERTY_APPEND,
1858         PROPERTY_REPLACE_EXISTING,
1859         PROPERTY_REJECT_FILE,
1860         PROPERTY_OVERWRITE_REJECTS,
1861         PROPERTY_CLEAR_BACKEND,
1862         PROPERTY_INCLUDE_BRANCH,
1863         PROPERTY_EXCLUDE_BRANCH,
1864         PROPERTY_INCLUDE_FILTER,
1865         PROPERTY_EXCLUDE_FILTER,
1866         PROPERTY_INCLUDE_ATTRIBUTE,
1867         PROPERTY_EXCLUDE_ATTRIBUTE,
1868         PROPERTY_IS_COMPRESSED,
1869         PROPERTY_IS_ENCRYPTED,
1870         PROPERTY_ENCRYPTION_PASSPHRASE_FILE,
1871         PROPERTY_SKIP_SCHEMA_VALIDATION,
1872         PROPERTY_STRIP_TRAILING_SPACES);
1873
1874    return Collections.unmodifiableList(propList);
1875  }
1876
1877
1878
1879  /**
1880   * {@inheritDoc}
1881   */
1882  @Override()
1883  @NotNull()
1884  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
1885  {
1886    final LinkedHashMap<TaskProperty,List<Object>> props =
1887         new LinkedHashMap<>(StaticUtils.computeMapCapacity(20));
1888
1889    if (backendID == null)
1890    {
1891      props.put(PROPERTY_BACKEND_ID, Collections.emptyList());
1892    }
1893    else
1894    {
1895      props.put(PROPERTY_BACKEND_ID,
1896                Collections.<Object>singletonList(backendID));
1897    }
1898
1899    props.put(PROPERTY_LDIF_FILE,
1900              Collections.<Object>unmodifiableList(ldifFiles));
1901
1902    props.put(PROPERTY_APPEND,
1903              Collections.<Object>singletonList(append));
1904
1905    props.put(PROPERTY_REPLACE_EXISTING,
1906              Collections.<Object>singletonList(replaceExisting));
1907
1908    if (rejectFile == null)
1909    {
1910      props.put(PROPERTY_REJECT_FILE, Collections.emptyList());
1911    }
1912    else
1913    {
1914      props.put(PROPERTY_REJECT_FILE,
1915                Collections.<Object>singletonList(rejectFile));
1916    }
1917
1918    props.put(PROPERTY_OVERWRITE_REJECTS,
1919              Collections.<Object>singletonList(overwriteRejects));
1920
1921    props.put(PROPERTY_CLEAR_BACKEND,
1922              Collections.<Object>singletonList(clearBackend));
1923
1924    props.put(PROPERTY_INCLUDE_BRANCH,
1925              Collections.<Object>unmodifiableList(includeBranches));
1926
1927    props.put(PROPERTY_EXCLUDE_BRANCH,
1928              Collections.<Object>unmodifiableList(excludeBranches));
1929
1930    props.put(PROPERTY_INCLUDE_FILTER,
1931              Collections.<Object>unmodifiableList(includeFilters));
1932
1933    props.put(PROPERTY_EXCLUDE_FILTER,
1934              Collections.<Object>unmodifiableList(excludeFilters));
1935
1936    props.put(PROPERTY_INCLUDE_ATTRIBUTE,
1937              Collections.<Object>unmodifiableList(includeAttributes));
1938
1939    props.put(PROPERTY_EXCLUDE_ATTRIBUTE,
1940              Collections.<Object>unmodifiableList(excludeAttributes));
1941
1942    props.put(PROPERTY_IS_COMPRESSED,
1943              Collections.<Object>singletonList(isCompressed));
1944
1945    props.put(PROPERTY_IS_ENCRYPTED,
1946              Collections.<Object>singletonList(isEncrypted));
1947
1948    if (encryptionPassphraseFile == null)
1949    {
1950      props.put(PROPERTY_ENCRYPTION_PASSPHRASE_FILE, Collections.emptyList());
1951    }
1952    else
1953    {
1954      props.put(PROPERTY_ENCRYPTION_PASSPHRASE_FILE,
1955         Collections.<Object>singletonList(encryptionPassphraseFile));
1956    }
1957
1958    props.put(PROPERTY_SKIP_SCHEMA_VALIDATION,
1959              Collections.<Object>singletonList(skipSchemaValidation));
1960
1961    props.put(PROPERTY_STRIP_TRAILING_SPACES,
1962              Collections.<Object>singletonList(stripTrailingSpaces));
1963
1964    props.putAll(super.getTaskPropertyValues());
1965    return Collections.unmodifiableMap(props);
1966  }
1967}