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