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