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