001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2006-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2013-2016 ForgeRock AS.
016 */
017package org.opends.server.tasks;
018
019import static org.opends.messages.TaskMessages.*;
020import static org.opends.messages.ToolMessages.*;
021import static org.opends.server.config.ConfigConstants.*;
022import static org.opends.server.core.DirectoryServer.*;
023import static org.opends.server.util.StaticUtils.*;
024
025import java.io.File;
026import java.util.ArrayList;
027import java.util.HashMap;
028import java.util.HashSet;
029import java.util.List;
030import java.util.Map;
031import java.util.Random;
032
033import org.forgerock.i18n.LocalizableMessage;
034import org.forgerock.i18n.slf4j.LocalizedLogger;
035import org.forgerock.opendj.ldap.DN;
036import org.forgerock.opendj.ldap.ResultCode;
037import org.forgerock.opendj.ldap.schema.AttributeType;
038import org.opends.messages.Severity;
039import org.opends.messages.TaskMessages;
040import org.opends.server.api.Backend;
041import org.opends.server.api.Backend.BackendOperation;
042import org.opends.server.api.ClientConnection;
043import org.opends.server.backends.task.Task;
044import org.opends.server.backends.task.TaskState;
045import org.opends.server.core.DirectoryServer;
046import org.opends.server.core.LockFileManager;
047import org.opends.server.tools.makeldif.TemplateFile;
048import org.opends.server.types.Attribute;
049import org.opends.server.types.DirectoryException;
050import org.opends.server.types.Entry;
051import org.opends.server.types.ExistingFileBehavior;
052import org.opends.server.types.LDIFImportConfig;
053import org.opends.server.types.Operation;
054import org.opends.server.types.Privilege;
055import org.opends.server.types.SearchFilter;
056
057/**
058 * This class provides an implementation of a Directory Server task that can
059 * be used to import data from an LDIF file into a backend.
060 */
061public class ImportTask extends Task
062{
063  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
064
065  /** Stores mapping between configuration attribute name and its label. */
066  private static final Map<String, LocalizableMessage> argDisplayMap = new HashMap<>();
067  static
068  {
069    argDisplayMap.put(ATTR_IMPORT_LDIF_FILE, INFO_IMPORT_ARG_LDIF_FILE.get());
070    argDisplayMap.put(ATTR_IMPORT_TEMPLATE_FILE, INFO_IMPORT_ARG_TEMPLATE_FILE.get());
071    argDisplayMap.put(ATTR_IMPORT_RANDOM_SEED, INFO_IMPORT_ARG_RANDOM_SEED.get());
072    argDisplayMap.put(ATTR_IMPORT_BACKEND_ID, INFO_IMPORT_ARG_BACKEND_ID.get());
073    argDisplayMap.put(ATTR_IMPORT_INCLUDE_BRANCH, INFO_IMPORT_ARG_INCL_BRANCH.get());
074    argDisplayMap.put(ATTR_IMPORT_EXCLUDE_BRANCH, INFO_IMPORT_ARG_EXCL_BRANCH.get());
075    argDisplayMap.put(ATTR_IMPORT_INCLUDE_ATTRIBUTE, INFO_IMPORT_ARG_INCL_ATTR.get());
076    argDisplayMap.put(ATTR_IMPORT_EXCLUDE_ATTRIBUTE, INFO_IMPORT_ARG_EXCL_ATTR.get());
077    argDisplayMap.put(ATTR_IMPORT_INCLUDE_FILTER, INFO_IMPORT_ARG_INCL_FILTER.get());
078    argDisplayMap.put(ATTR_IMPORT_EXCLUDE_FILTER, INFO_IMPORT_ARG_EXCL_FILTER.get());
079    argDisplayMap.put(ATTR_IMPORT_REJECT_FILE, INFO_IMPORT_ARG_REJECT_FILE.get());
080    argDisplayMap.put(ATTR_IMPORT_SKIP_FILE, INFO_IMPORT_ARG_SKIP_FILE.get());
081    argDisplayMap.put(ATTR_IMPORT_OVERWRITE, INFO_IMPORT_ARG_OVERWRITE.get());
082    argDisplayMap.put(ATTR_IMPORT_SKIP_SCHEMA_VALIDATION, INFO_IMPORT_ARG_SKIP_SCHEMA_VALIDATION.get());
083    argDisplayMap.put(ATTR_IMPORT_IS_COMPRESSED, INFO_IMPORT_ARG_IS_COMPRESSED.get());
084    argDisplayMap.put(ATTR_IMPORT_IS_ENCRYPTED, INFO_IMPORT_ARG_IS_ENCRYPTED.get());
085    argDisplayMap.put(ATTR_IMPORT_CLEAR_BACKEND, INFO_IMPORT_ARG_CLEAR_BACKEND.get());
086  }
087
088  private boolean isCompressed;
089  private boolean isEncrypted;
090  private boolean overwrite;
091  private boolean skipSchemaValidation;
092  private boolean clearBackend;
093  private String tmpDirectory;
094  private int threadCount;
095  private String backendID;
096  private String rejectFile;
097  private String skipFile;
098  private ArrayList<String> excludeAttributeStrings;
099  private ArrayList<String> excludeBranchStrings;
100  private ArrayList<String> excludeFilterStrings;
101  private ArrayList<String> includeAttributeStrings;
102  private ArrayList<String> includeBranchStrings;
103  private ArrayList<String> includeFilterStrings;
104  private ArrayList<String> ldifFiles;
105  private String templateFile;
106  private int randomSeed;
107  private LDIFImportConfig importConfig;
108
109  @Override
110  public LocalizableMessage getDisplayName() {
111    return INFO_TASK_IMPORT_NAME.get();
112  }
113
114  @Override
115  public LocalizableMessage getAttributeDisplayName(String name) {
116    return argDisplayMap.get(name);
117  }
118
119  @Override public void initializeTask() throws DirectoryException
120  {
121    // If the client connection is available, then make sure the associated
122    // client has the LDIF_IMPORT privilege.
123    Operation operation = getOperation();
124    if (operation != null)
125    {
126      ClientConnection clientConnection = operation.getClientConnection();
127      if (! clientConnection.hasPrivilege(Privilege.LDIF_IMPORT, operation))
128      {
129        LocalizableMessage message = ERR_TASK_LDIFIMPORT_INSUFFICIENT_PRIVILEGES.get();
130        throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS, message);
131      }
132    }
133
134    Entry taskEntry = getTaskEntry();
135
136    AttributeType typeLdifFile = getSchema().getAttributeType(ATTR_IMPORT_LDIF_FILE);
137    AttributeType typeTemplateFile = getSchema().getAttributeType(ATTR_IMPORT_TEMPLATE_FILE);
138    AttributeType typeBackendID = getSchema().getAttributeType(ATTR_IMPORT_BACKEND_ID);
139    AttributeType typeIncludeBranch = getSchema().getAttributeType(ATTR_IMPORT_INCLUDE_BRANCH);
140    AttributeType typeExcludeBranch = getSchema().getAttributeType(ATTR_IMPORT_EXCLUDE_BRANCH);
141    AttributeType typeIncludeAttribute = getSchema().getAttributeType(ATTR_IMPORT_INCLUDE_ATTRIBUTE);
142    AttributeType typeExcludeAttribute = getSchema().getAttributeType(ATTR_IMPORT_EXCLUDE_ATTRIBUTE);
143    AttributeType typeIncludeFilter = getSchema().getAttributeType(ATTR_IMPORT_INCLUDE_FILTER);
144    AttributeType typeExcludeFilter = getSchema().getAttributeType(ATTR_IMPORT_EXCLUDE_FILTER);
145    AttributeType typeRejectFile = getSchema().getAttributeType(ATTR_IMPORT_REJECT_FILE);
146    AttributeType typeSkipFile = getSchema().getAttributeType(ATTR_IMPORT_SKIP_FILE);
147    AttributeType typeOverwrite = getSchema().getAttributeType(ATTR_IMPORT_OVERWRITE);
148    AttributeType typeSkipSchemaValidation = getSchema().getAttributeType(ATTR_IMPORT_SKIP_SCHEMA_VALIDATION);
149    AttributeType typeIsCompressed = getSchema().getAttributeType(ATTR_IMPORT_IS_COMPRESSED);
150    AttributeType typeIsEncrypted = getSchema().getAttributeType(ATTR_IMPORT_IS_ENCRYPTED);
151    AttributeType typeClearBackend = getSchema().getAttributeType(ATTR_IMPORT_CLEAR_BACKEND);
152    AttributeType typeRandomSeed = getSchema().getAttributeType(ATTR_IMPORT_RANDOM_SEED);
153    AttributeType typeThreadCount = getSchema().getAttributeType(ATTR_IMPORT_THREAD_COUNT);
154    AttributeType typeTmpDirectory = getSchema().getAttributeType(ATTR_IMPORT_TMP_DIRECTORY);
155
156    ArrayList<String> ldifFilestmp = asListOfStrings(taskEntry, typeLdifFile);
157    ldifFiles = new ArrayList<>(ldifFilestmp.size());
158    for (String s : ldifFilestmp)
159    {
160      File f = new File (s);
161      if (!f.isAbsolute())
162      {
163        f = new File(DirectoryServer.getInstanceRoot(), s);
164        try
165        {
166          s = f.getCanonicalPath();
167        }
168        catch (Exception ex)
169        {
170          s = f.getAbsolutePath();
171        }
172      }
173      if (!f.canRead()) {
174        LocalizableMessage message = ERR_LDIFIMPORT_LDIF_FILE_DOESNT_EXIST.get(s);
175        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
176      }
177      ldifFiles.add(s);
178    }
179
180    templateFile = asString(taskEntry, typeTemplateFile);
181    if (templateFile != null)
182    {
183      File f = new File(templateFile);
184      if (!f.isAbsolute())
185      {
186        templateFile = new File(DirectoryServer.getInstanceRoot(), templateFile).getAbsolutePath();
187      }
188    }
189
190    tmpDirectory = asString(taskEntry, typeTmpDirectory);
191    backendID = asString(taskEntry, typeBackendID);
192    includeBranchStrings = asListOfStrings(taskEntry, typeIncludeBranch);
193    excludeBranchStrings = asListOfStrings(taskEntry, typeExcludeBranch);
194    includeAttributeStrings = asListOfStrings(taskEntry, typeIncludeAttribute);
195    excludeAttributeStrings = asListOfStrings(taskEntry, typeExcludeAttribute);
196    includeFilterStrings = asListOfStrings(taskEntry, typeIncludeFilter);
197    excludeFilterStrings = asListOfStrings(taskEntry, typeExcludeFilter);
198    rejectFile = asString(taskEntry, typeRejectFile);
199    skipFile = asString(taskEntry, typeSkipFile);
200    overwrite = asBoolean(taskEntry, typeOverwrite);
201    skipSchemaValidation = asBoolean(taskEntry, typeSkipSchemaValidation);
202    isCompressed = asBoolean(taskEntry, typeIsCompressed);
203    isEncrypted = asBoolean(taskEntry, typeIsEncrypted);
204    clearBackend = asBoolean(taskEntry, typeClearBackend);
205    randomSeed = asInt(taskEntry, typeRandomSeed);
206    threadCount = asInt(taskEntry, typeThreadCount);
207
208    // Make sure that either the "includeBranchStrings" argument or the
209    // "backendID" argument was provided.
210    if(includeBranchStrings.isEmpty() && backendID == null)
211    {
212      LocalizableMessage message = ERR_LDIFIMPORT_MISSING_BACKEND_ARGUMENT.get(
213          typeIncludeBranch.getNameOrOID(), typeBackendID.getNameOrOID());
214      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
215    }
216
217    Backend<?> backend = null;
218    ArrayList<DN> defaultIncludeBranches;
219    HashSet<DN> excludeBranches = new HashSet<>(excludeBranchStrings.size());
220    HashSet<DN> includeBranches = new HashSet<>(includeBranchStrings.size());
221
222    for (String s : includeBranchStrings)
223    {
224      DN includeBranch;
225      try
226      {
227        includeBranch = DN.valueOf(s);
228      }
229      catch (Exception e)
230      {
231        LocalizableMessage message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get(
232            s, getExceptionMessage(e));
233        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
234      }
235
236      includeBranches.add(includeBranch);
237    }
238    for (String s : excludeBranchStrings)
239    {
240      DN excludeBranch;
241      try
242      {
243        excludeBranch = DN.valueOf(s);
244      }
245      catch (Exception e)
246      {
247        LocalizableMessage message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get(
248            s, getExceptionMessage(e));
249        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
250      }
251
252      excludeBranches.add(excludeBranch);
253    }
254
255    for (String filterString : excludeFilterStrings)
256    {
257      try
258      {
259        SearchFilter.createFilterFromString(filterString);
260      }
261      catch (DirectoryException de)
262      {
263        LocalizableMessage message = ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER.get(
264            filterString, de.getMessageObject());
265        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
266      }
267    }
268
269    for (String filterString : includeFilterStrings)
270    {
271      try
272      {
273        SearchFilter.createFilterFromString(filterString);
274      }
275      catch (DirectoryException de)
276      {
277        LocalizableMessage message = ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER.get(
278            filterString, de.getMessageObject());
279        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
280      }
281    }
282
283    if(backendID != null)
284    {
285      backend = DirectoryServer.getBackend(backendID);
286      if (backend == null)
287      {
288        LocalizableMessage message = ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID.get();
289        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
290      }
291      else if (!backend.supports(BackendOperation.LDIF_IMPORT))
292      {
293        LocalizableMessage message = ERR_LDIFIMPORT_CANNOT_IMPORT.get(backendID);
294        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
295      }
296    }
297    else
298    {
299      // Find the backend that includes all the branches.
300      for(DN includeBranch : includeBranches)
301      {
302        Backend<?> locatedBackend = DirectoryServer.getBackend(includeBranch);
303        if(locatedBackend != null)
304        {
305          if(backend == null)
306          {
307            backend = locatedBackend;
308          }
309          else if(backend != locatedBackend)
310          {
311            // The include branches span across multiple backends.
312            LocalizableMessage message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get(
313                includeBranch, backend.getBackendID());
314            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
315          }
316        }
317        else
318        {
319          // The include branch is not associated with any backend.
320          LocalizableMessage message = ERR_NO_BACKENDS_FOR_BASE.get(includeBranch);
321          throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
322        }
323      }
324    }
325
326    // Make sure the selected backend will handle all the include branches
327    defaultIncludeBranches = new ArrayList<>(backend.getBaseDNs());
328
329    for(DN includeBranch : includeBranches)
330    {
331      if (!Backend.handlesEntry(includeBranch, defaultIncludeBranches, excludeBranches))
332      {
333        LocalizableMessage message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get(
334            includeBranch, backend.getBackendID());
335        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
336      }
337    }
338  }
339
340  private int asInt(Entry taskEntry, AttributeType attributeType)
341  {
342    final List<Attribute> attrList = taskEntry.getAttribute(attributeType);
343    return TaskUtils.getSingleValueInteger(attrList, 0);
344  }
345
346  private boolean asBoolean(Entry taskEntry, AttributeType attributeType)
347  {
348    final List<Attribute> attrList = taskEntry.getAttribute(attributeType);
349    return TaskUtils.getBoolean(attrList, false);
350  }
351
352  private String asString(Entry taskEntry, AttributeType attributeType)
353  {
354    final List<Attribute> attrList = taskEntry.getAttribute(attributeType);
355    return TaskUtils.getSingleValueString(attrList);
356  }
357
358  private ArrayList<String> asListOfStrings(Entry taskEntry, AttributeType attributeType)
359  {
360    final List<Attribute> attrList = taskEntry.getAttribute(attributeType);
361    return TaskUtils.getMultiValueString(attrList);
362  }
363
364  @Override
365  public void interruptTask(TaskState interruptState, LocalizableMessage interruptReason)
366  {
367    if (TaskState.STOPPED_BY_ADMINISTRATOR.equals(interruptState) && importConfig != null)
368    {
369      addLogMessage(Severity.INFORMATION, TaskMessages.INFO_TASK_STOPPED_BY_ADMIN.get(
370      interruptReason));
371      setTaskInterruptState(interruptState);
372      importConfig.cancel();
373    }
374  }
375
376  @Override
377  public boolean isInterruptable()
378  {
379    return true;
380  }
381
382  @Override
383  protected TaskState runTask()
384  {
385    // See if there were any user-defined sets of include/exclude attributes or
386    // filters.  If so, then process them.
387    HashSet<AttributeType> excludeAttributes = toAttributeTypes(excludeAttributeStrings);
388    HashSet<AttributeType> includeAttributes = toAttributeTypes(includeAttributeStrings);
389
390    ArrayList<SearchFilter> excludeFilters = new ArrayList<>(excludeFilterStrings.size());
391    for (String filterString : excludeFilterStrings)
392    {
393      try
394      {
395        excludeFilters.add(SearchFilter.createFilterFromString(filterString));
396      }
397      catch (DirectoryException de)
398      {
399        logger.error(ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER, filterString, de.getMessageObject());
400        return TaskState.STOPPED_BY_ERROR;
401      }
402    }
403
404    ArrayList<SearchFilter> includeFilters = new ArrayList<>(includeFilterStrings.size());
405    for (String filterString : includeFilterStrings)
406    {
407      try
408      {
409        includeFilters.add(SearchFilter.createFilterFromString(filterString));
410      }
411      catch (DirectoryException de)
412      {
413        logger.error(ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER, filterString, de.getMessageObject());
414        return TaskState.STOPPED_BY_ERROR;
415      }
416    }
417
418    // Get the backend into which the LDIF should be imported.
419    Backend<?> backend = null;
420    HashSet<DN> defaultIncludeBranches;
421    HashSet<DN> excludeBranches = new HashSet<>(excludeBranchStrings.size());
422    HashSet<DN> includeBranches = new HashSet<>(includeBranchStrings.size());
423
424    for (String s : includeBranchStrings)
425    {
426      DN includeBranch;
427      try
428      {
429        includeBranch = DN.valueOf(s);
430      }
431      catch (Exception e)
432      {
433        logger.error(ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE, s, getExceptionMessage(e));
434        return TaskState.STOPPED_BY_ERROR;
435      }
436
437      includeBranches.add(includeBranch);
438    }
439
440    if(backendID != null)
441    {
442      backend = DirectoryServer.getBackend(backendID);
443
444      if (backend == null)
445      {
446        logger.error(ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID);
447        return TaskState.STOPPED_BY_ERROR;
448      }
449      else if (!backend.supports(BackendOperation.LDIF_IMPORT))
450      {
451        logger.error(ERR_LDIFIMPORT_CANNOT_IMPORT, backendID);
452        return TaskState.STOPPED_BY_ERROR;
453      }
454    }
455    else
456    {
457      // Find the backend that includes all the branches.
458      for(DN includeBranch : includeBranches)
459      {
460        Backend<?> locatedBackend = DirectoryServer.getBackend(includeBranch);
461        if(locatedBackend != null)
462        {
463          if(backend == null)
464          {
465            backend = locatedBackend;
466          }
467          else if(backend != locatedBackend)
468          {
469            // The include branches span across multiple backends.
470            logger.error(ERR_LDIFIMPORT_INVALID_INCLUDE_BASE, includeBranch, backend.getBackendID());
471            return TaskState.STOPPED_BY_ERROR;
472          }
473        }
474      }
475    }
476
477    // Find backends with subordinate base DNs that should be excluded from the import.
478    defaultIncludeBranches = new HashSet<>(backend.getBaseDNs());
479
480    if (backend.getSubordinateBackends() != null)
481    {
482      for (Backend<?> subBackend : backend.getSubordinateBackends())
483      {
484        for (DN baseDN : subBackend.getBaseDNs())
485        {
486          for (DN importBase : defaultIncludeBranches)
487          {
488            if (!baseDN.equals(importBase) && baseDN.isSubordinateOrEqualTo(importBase))
489            {
490              excludeBranches.add(baseDN);
491              break;
492            }
493          }
494        }
495      }
496    }
497
498    for (String s : excludeBranchStrings)
499    {
500      DN excludeBranch;
501      try
502      {
503        excludeBranch = DN.valueOf(s);
504      }
505      catch (Exception e)
506      {
507        logger.error(ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE, s, getExceptionMessage(e));
508        return TaskState.STOPPED_BY_ERROR;
509      }
510
511      excludeBranches.add(excludeBranch);
512    }
513
514    if (includeBranchStrings.isEmpty())
515    {
516      includeBranches = defaultIncludeBranches;
517    }
518    else
519    {
520      // Make sure the selected backend will handle all the include branches
521      for (DN includeBranch : includeBranches)
522      {
523        if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches,
524                                   excludeBranches))
525        {
526          logger.error(ERR_LDIFIMPORT_INVALID_INCLUDE_BASE, includeBranch, backend.getBackendID());
527          return TaskState.STOPPED_BY_ERROR;
528        }
529      }
530    }
531
532    // Create the LDIF import configuration to use when reading the LDIF.
533    if (templateFile != null)
534    {
535      Random random;
536      try
537      {
538        random = new Random(randomSeed);
539      }
540      catch (Exception e)
541      {
542        random = new Random();
543      }
544
545      String resourcePath = DirectoryServer.getInstanceRoot() + File.separator +
546                            PATH_MAKELDIF_RESOURCE_DIR;
547      TemplateFile tf = new TemplateFile(resourcePath, random);
548
549      ArrayList<LocalizableMessage> warnings = new ArrayList<>();
550      try
551      {
552        tf.parse(templateFile, warnings);
553      }
554      catch (Exception e)
555      {
556        logger.error(ERR_LDIFIMPORT_CANNOT_PARSE_TEMPLATE_FILE, templateFile, e.getMessage());
557        return TaskState.STOPPED_BY_ERROR;
558      }
559
560      importConfig = new LDIFImportConfig(tf);
561    }
562    else
563    {
564      ArrayList<String> fileList = new ArrayList<>(ldifFiles);
565      importConfig = new LDIFImportConfig(fileList);
566    }
567    if(tmpDirectory == null)
568    {
569      tmpDirectory = "import-tmp";
570    }
571    importConfig.setCompressed(isCompressed);
572    importConfig.setEncrypted(isEncrypted);
573    importConfig.setClearBackend(clearBackend);
574    importConfig.setExcludeAttributes(excludeAttributes);
575    importConfig.setExcludeBranches(excludeBranches);
576    importConfig.setExcludeFilters(excludeFilters);
577    importConfig.setIncludeAttributes(includeAttributes);
578    importConfig.setIncludeBranches(includeBranches);
579    importConfig.setIncludeFilters(includeFilters);
580    importConfig.setValidateSchema(!skipSchemaValidation);
581    importConfig.setTmpDirectory(tmpDirectory);
582    importConfig.setThreadCount(threadCount);
583
584    // FIXME -- Should this be conditional?
585    importConfig.setInvokeImportPlugins(true);
586
587    if (rejectFile != null)
588    {
589      try
590      {
591        ExistingFileBehavior existingBehavior =
592            overwrite ? ExistingFileBehavior.OVERWRITE : ExistingFileBehavior.APPEND;
593
594        importConfig.writeRejectedEntries(rejectFile, existingBehavior);
595      }
596      catch (Exception e)
597      {
598        logger.error(ERR_LDIFIMPORT_CANNOT_OPEN_REJECTS_FILE, rejectFile, getExceptionMessage(e));
599        return TaskState.STOPPED_BY_ERROR;
600      }
601    }
602
603    if (skipFile != null)
604    {
605      try
606      {
607        ExistingFileBehavior existingBehavior =
608            overwrite ? ExistingFileBehavior.OVERWRITE : ExistingFileBehavior.APPEND;
609        importConfig.writeSkippedEntries(skipFile, existingBehavior);
610      }
611      catch (Exception e)
612      {
613        logger.error(ERR_LDIFIMPORT_CANNOT_OPEN_SKIP_FILE, skipFile, getExceptionMessage(e));
614        return TaskState.STOPPED_BY_ERROR;
615      }
616    }
617
618    // Notify the task listeners that an import is going to start
619    // this must be done before disabling the backend to allow
620    // listeners to get access to the backend configuration
621    // and to take appropriate actions.
622    DirectoryServer.notifyImportBeginning(backend, importConfig);
623
624    // Disable the backend.
625    try
626    {
627      TaskUtils.disableBackend(backend.getBackendID());
628    }
629    catch (DirectoryException e)
630    {
631      logger.traceException(e);
632
633      logger.error(e.getMessageObject());
634      return TaskState.STOPPED_BY_ERROR;
635    }
636
637    try
638    {
639      // Acquire an exclusive lock for the backend.
640      try
641      {
642        String lockFile = LockFileManager.getBackendLockFileName(backend);
643        StringBuilder failureReason = new StringBuilder();
644        if (! LockFileManager.acquireExclusiveLock(lockFile, failureReason))
645        {
646          logger.error(ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND, backend.getBackendID(), failureReason);
647          return TaskState.STOPPED_BY_ERROR;
648        }
649      }
650      catch (Exception e)
651      {
652        logger.traceException(e);
653
654        logger.error(ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND, backend.getBackendID(), getExceptionMessage(e));
655        return TaskState.STOPPED_BY_ERROR;
656      }
657
658      // Launch the import.
659      try
660      {
661        backend.importLDIF(importConfig, DirectoryServer.getInstance().getServerContext());
662      }
663      catch (DirectoryException de)
664      {
665        logger.traceException(de);
666
667        DirectoryServer.notifyImportEnded(backend, importConfig, false);
668        logger.error(ERR_LDIFIMPORT_ERROR_DURING_IMPORT.get(de.getMessageObject()));
669        return TaskState.STOPPED_BY_ERROR;
670      }
671      catch (Exception e)
672      {
673        logger.traceException(e);
674
675        DirectoryServer.notifyImportEnded(backend, importConfig, false);
676        logger.error(ERR_LDIFIMPORT_ERROR_DURING_IMPORT, getExceptionMessage(e));
677        return TaskState.STOPPED_BY_ERROR;
678      }
679      finally
680      {
681        // Release the exclusive lock on the backend.
682        try
683        {
684          String lockFile = LockFileManager.getBackendLockFileName(backend);
685          StringBuilder failureReason = new StringBuilder();
686          if (! LockFileManager.releaseLock(lockFile, failureReason))
687          {
688            logger.warn(WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND, backend.getBackendID(), failureReason);
689            return TaskState.COMPLETED_WITH_ERRORS;
690          }
691        }
692        catch (Exception e)
693        {
694          logger.traceException(e);
695
696          logger.warn(WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND, backend.getBackendID(), getExceptionMessage(e));
697          return TaskState.COMPLETED_WITH_ERRORS;
698        }
699      }
700    }
701    finally
702    {
703      // Enable the backend.
704      try
705      {
706        TaskUtils.enableBackend(backend.getBackendID());
707        // It is necessary to retrieve the backend structure again
708        // because disabling and enabling it again may have resulted
709        // in a new backend being registered to the server.
710        backend = DirectoryServer.getBackend(backend.getBackendID());
711      }
712      catch (DirectoryException e)
713      {
714        logger.traceException(e);
715
716        logger.error(e.getMessageObject());
717        return TaskState.STOPPED_BY_ERROR;
718      }
719      DirectoryServer.notifyImportEnded(backend, importConfig, true);
720    }
721
722    // Clean up after the import by closing the import config.
723    importConfig.close();
724    return getFinalTaskState();
725  }
726
727  private HashSet<AttributeType> toAttributeTypes(ArrayList<String> attrNames)
728  {
729    final HashSet<AttributeType> attrTypes = new HashSet<>(attrNames.size());
730    for (String attrName : attrNames)
731    {
732      attrTypes.add(DirectoryServer.getSchema().getAttributeType(attrName));
733    }
734    return attrTypes;
735  }
736}