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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.tasks; 028 import org.opends.messages.Message; 029 import org.opends.messages.TaskMessages; 030 031 import static org.opends.messages.TaskMessages.*; 032 import static org.opends.messages.ToolMessages.*; 033 import static org.opends.server.loggers.debug.DebugLogger.*; 034 import org.opends.server.loggers.debug.DebugTracer; 035 import org.opends.server.types.DebugLogLevel; 036 import static org.opends.server.util.StaticUtils.*; 037 import static org.opends.server.config.ConfigConstants.*; 038 import static org.opends.server.core.DirectoryServer.getAttributeType; 039 040 import org.opends.server.backends.task.Task; 041 import org.opends.server.backends.task.TaskState; 042 import org.opends.server.core.DirectoryServer; 043 import org.opends.server.core.LockFileManager; 044 import org.opends.server.api.Backend; 045 import org.opends.server.api.ClientConnection; 046 import org.opends.server.types.Attribute; 047 import org.opends.server.types.AttributeType; 048 import org.opends.server.types.DirectoryException; 049 import org.opends.server.types.DN; 050 import org.opends.server.types.Entry; 051 052 053 import org.opends.server.types.ExistingFileBehavior; 054 import org.opends.server.types.LDIFImportConfig; 055 import org.opends.server.types.Operation; 056 import org.opends.server.types.Privilege; 057 import org.opends.server.types.ResultCode; 058 import org.opends.server.types.SearchFilter; 059 060 import java.util.HashSet; 061 import java.util.ArrayList; 062 import java.util.List; 063 import java.util.Map; 064 import java.util.HashMap; 065 066 /** 067 * This class provides an implementation of a Directory Server task that can 068 * be used to import data from an LDIF file into a backend. 069 */ 070 public class ImportTask extends Task 071 { 072 /** 073 * The tracer object for the debug logger. 074 */ 075 private static final DebugTracer TRACER = getTracer(); 076 077 078 /** 079 * Stores mapping between configuration attribute name and its label. 080 */ 081 static private Map<String,Message> argDisplayMap = 082 new HashMap<String,Message>(); 083 084 static { 085 argDisplayMap.put( 086 ATTR_IMPORT_LDIF_FILE, 087 INFO_IMPORT_ARG_LDIF_FILE.get()); 088 089 argDisplayMap.put( 090 ATTR_IMPORT_APPEND, 091 INFO_IMPORT_ARG_APPEND.get()); 092 093 argDisplayMap.put( 094 ATTR_IMPORT_REPLACE_EXISTING, 095 INFO_IMPORT_ARG_REPLACE_EXISTING.get()); 096 097 argDisplayMap.put( 098 ATTR_IMPORT_BACKEND_ID, 099 INFO_IMPORT_ARG_BACKEND_ID.get()); 100 101 argDisplayMap.put( 102 ATTR_IMPORT_INCLUDE_BRANCH, 103 INFO_IMPORT_ARG_INCL_BRANCH.get()); 104 105 argDisplayMap.put( 106 ATTR_IMPORT_EXCLUDE_BRANCH, 107 INFO_IMPORT_ARG_EXCL_BRANCH.get()); 108 109 argDisplayMap.put( 110 ATTR_IMPORT_INCLUDE_ATTRIBUTE, 111 INFO_IMPORT_ARG_INCL_ATTR.get()); 112 113 argDisplayMap.put( 114 ATTR_IMPORT_EXCLUDE_ATTRIBUTE, 115 INFO_IMPORT_ARG_EXCL_ATTR.get()); 116 117 argDisplayMap.put( 118 ATTR_IMPORT_INCLUDE_FILTER, 119 INFO_IMPORT_ARG_INCL_FILTER.get()); 120 121 argDisplayMap.put( 122 ATTR_IMPORT_EXCLUDE_FILTER, 123 INFO_IMPORT_ARG_EXCL_FILTER.get()); 124 125 argDisplayMap.put( 126 ATTR_IMPORT_REJECT_FILE, 127 INFO_IMPORT_ARG_REJECT_FILE.get()); 128 129 argDisplayMap.put( 130 ATTR_IMPORT_SKIP_FILE, 131 INFO_IMPORT_ARG_SKIP_FILE.get()); 132 133 argDisplayMap.put( 134 ATTR_IMPORT_OVERWRITE, 135 INFO_IMPORT_ARG_OVERWRITE.get()); 136 137 argDisplayMap.put( 138 ATTR_IMPORT_SKIP_SCHEMA_VALIDATION, 139 INFO_IMPORT_ARG_SKIP_SCHEMA_VALIDATION.get()); 140 141 argDisplayMap.put( 142 ATTR_IMPORT_IS_COMPRESSED, 143 INFO_IMPORT_ARG_IS_COMPRESSED.get()); 144 145 argDisplayMap.put( 146 ATTR_IMPORT_IS_ENCRYPTED, 147 INFO_IMPORT_ARG_IS_ENCRYPTED.get()); 148 149 argDisplayMap.put( 150 ATTR_IMPORT_CLEAR_BACKEND, 151 INFO_IMPORT_ARG_CLEAR_BACKEND.get()); 152 } 153 154 155 boolean append = false; 156 boolean isCompressed = false; 157 boolean isEncrypted = false; 158 boolean overwrite = false; 159 boolean replaceExisting = false; 160 boolean skipSchemaValidation = false; 161 boolean clearBackend = false; 162 String backendID = null; 163 String rejectFile = null; 164 String skipFile = null; 165 ArrayList<String> excludeAttributeStrings = null; 166 ArrayList<String> excludeBranchStrings = null; 167 ArrayList<String> excludeFilterStrings = null; 168 ArrayList<String> includeAttributeStrings = null; 169 ArrayList<String> includeBranchStrings = null; 170 ArrayList<String> includeFilterStrings = null; 171 ArrayList<String> ldifFiles = null; 172 173 private LDIFImportConfig importConfig; 174 175 /** 176 * {@inheritDoc} 177 */ 178 public Message getDisplayName() { 179 return INFO_TASK_IMPORT_NAME.get(); 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 public Message getAttributeDisplayName(String name) { 186 return argDisplayMap.get(name); 187 } 188 189 /** 190 * {@inheritDoc} 191 */ 192 @Override public void initializeTask() throws DirectoryException 193 { 194 // If the client connection is available, then make sure the associated 195 // client has the LDIF_IMPORT privilege. 196 Operation operation = getOperation(); 197 if (operation != null) 198 { 199 ClientConnection clientConnection = operation.getClientConnection(); 200 if (! clientConnection.hasPrivilege(Privilege.LDIF_IMPORT, operation)) 201 { 202 Message message = ERR_TASK_LDIFIMPORT_INSUFFICIENT_PRIVILEGES.get(); 203 throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS, 204 message); 205 } 206 } 207 208 209 Entry taskEntry = getTaskEntry(); 210 211 AttributeType typeLdifFile; 212 AttributeType typeAppend; 213 AttributeType typeReplaceExisting; 214 AttributeType typeBackendID; 215 AttributeType typeIncludeBranch; 216 AttributeType typeExcludeBranch; 217 AttributeType typeIncludeAttribute; 218 AttributeType typeExcludeAttribute; 219 AttributeType typeIncludeFilter; 220 AttributeType typeExcludeFilter; 221 AttributeType typeRejectFile; 222 AttributeType typeSkipFile; 223 AttributeType typeOverwrite; 224 AttributeType typeSkipSchemaValidation; 225 AttributeType typeIsCompressed; 226 AttributeType typeIsEncrypted; 227 AttributeType typeClearBackend; 228 229 typeLdifFile = 230 getAttributeType(ATTR_IMPORT_LDIF_FILE, true); 231 typeAppend = 232 getAttributeType(ATTR_IMPORT_APPEND, true); 233 typeReplaceExisting = 234 getAttributeType(ATTR_IMPORT_REPLACE_EXISTING, true); 235 typeBackendID = 236 getAttributeType(ATTR_IMPORT_BACKEND_ID, true); 237 typeIncludeBranch = 238 getAttributeType(ATTR_IMPORT_INCLUDE_BRANCH, true); 239 typeExcludeBranch = 240 getAttributeType(ATTR_IMPORT_EXCLUDE_BRANCH, true); 241 typeIncludeAttribute = 242 getAttributeType(ATTR_IMPORT_INCLUDE_ATTRIBUTE, true); 243 typeExcludeAttribute = 244 getAttributeType(ATTR_IMPORT_EXCLUDE_ATTRIBUTE, true); 245 typeIncludeFilter = 246 getAttributeType(ATTR_IMPORT_INCLUDE_FILTER, true); 247 typeExcludeFilter = 248 getAttributeType(ATTR_IMPORT_EXCLUDE_FILTER, true); 249 typeRejectFile = 250 getAttributeType(ATTR_IMPORT_REJECT_FILE, true); 251 typeSkipFile = 252 getAttributeType(ATTR_IMPORT_SKIP_FILE, true); 253 typeOverwrite = 254 getAttributeType(ATTR_IMPORT_OVERWRITE, true); 255 typeSkipSchemaValidation = 256 getAttributeType(ATTR_IMPORT_SKIP_SCHEMA_VALIDATION, true); 257 typeIsCompressed = 258 getAttributeType(ATTR_IMPORT_IS_COMPRESSED, true); 259 typeIsEncrypted = 260 getAttributeType(ATTR_IMPORT_IS_ENCRYPTED, true); 261 typeClearBackend = 262 getAttributeType(ATTR_IMPORT_CLEAR_BACKEND, true); 263 264 List<Attribute> attrList; 265 266 attrList = taskEntry.getAttribute(typeLdifFile); 267 ldifFiles = TaskUtils.getMultiValueString(attrList); 268 269 attrList = taskEntry.getAttribute(typeAppend); 270 append = TaskUtils.getBoolean(attrList, false); 271 272 attrList = taskEntry.getAttribute(typeReplaceExisting); 273 replaceExisting = TaskUtils.getBoolean(attrList, false); 274 275 attrList = taskEntry.getAttribute(typeBackendID); 276 backendID = TaskUtils.getSingleValueString(attrList); 277 278 attrList = taskEntry.getAttribute(typeIncludeBranch); 279 includeBranchStrings = TaskUtils.getMultiValueString(attrList); 280 281 attrList = taskEntry.getAttribute(typeExcludeBranch); 282 excludeBranchStrings = TaskUtils.getMultiValueString(attrList); 283 284 attrList = taskEntry.getAttribute(typeIncludeAttribute); 285 includeAttributeStrings = TaskUtils.getMultiValueString(attrList); 286 287 attrList = taskEntry.getAttribute(typeExcludeAttribute); 288 excludeAttributeStrings = TaskUtils.getMultiValueString(attrList); 289 290 attrList = taskEntry.getAttribute(typeIncludeFilter); 291 includeFilterStrings = TaskUtils.getMultiValueString(attrList); 292 293 attrList = taskEntry.getAttribute(typeExcludeFilter); 294 excludeFilterStrings = TaskUtils.getMultiValueString(attrList); 295 296 attrList = taskEntry.getAttribute(typeRejectFile); 297 rejectFile = TaskUtils.getSingleValueString(attrList); 298 299 attrList = taskEntry.getAttribute(typeSkipFile); 300 skipFile = TaskUtils.getSingleValueString(attrList); 301 302 attrList = taskEntry.getAttribute(typeOverwrite); 303 overwrite = TaskUtils.getBoolean(attrList, false); 304 305 attrList = taskEntry.getAttribute(typeSkipSchemaValidation); 306 skipSchemaValidation = TaskUtils.getBoolean(attrList, false); 307 308 attrList = taskEntry.getAttribute(typeIsCompressed); 309 isCompressed = TaskUtils.getBoolean(attrList, false); 310 311 attrList = taskEntry.getAttribute(typeIsEncrypted); 312 isEncrypted = TaskUtils.getBoolean(attrList, false); 313 314 attrList = taskEntry.getAttribute(typeClearBackend); 315 clearBackend = TaskUtils.getBoolean(attrList, false); 316 317 // Make sure that either the "includeBranchStrings" argument or the 318 // "backendID" argument was provided. 319 if(includeBranchStrings.isEmpty() && backendID == null) 320 { 321 Message message = ERR_LDIFIMPORT_MISSING_BACKEND_ARGUMENT.get( 322 typeIncludeBranch.getNameOrOID(), typeBackendID.getNameOrOID()); 323 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 324 } 325 326 Backend backend = null; 327 ArrayList<DN> defaultIncludeBranches; 328 ArrayList<DN> excludeBranches = 329 new ArrayList<DN>(excludeBranchStrings.size()); 330 ArrayList<DN> includeBranches = 331 new ArrayList<DN>(includeBranchStrings.size()); 332 333 for (String s : includeBranchStrings) 334 { 335 DN includeBranch; 336 try 337 { 338 includeBranch = DN.decode(s); 339 } 340 catch (DirectoryException de) 341 { 342 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get( 343 s, de.getMessageObject()); 344 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 345 } 346 catch (Exception e) 347 { 348 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get( 349 s, getExceptionMessage(e)); 350 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 351 } 352 353 if(! includeBranches.contains(includeBranch)) 354 { 355 includeBranches.add(includeBranch); 356 } 357 } 358 for (String s : excludeBranchStrings) 359 { 360 DN excludeBranch; 361 try 362 { 363 excludeBranch = DN.decode(s); 364 } 365 catch (DirectoryException de) 366 { 367 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get( 368 s, de.getMessageObject()); 369 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 370 } 371 catch (Exception e) 372 { 373 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get( 374 s, getExceptionMessage(e)); 375 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 376 } 377 378 if (! excludeBranches.contains(excludeBranch)) 379 { 380 excludeBranches.add(excludeBranch); 381 } 382 } 383 384 for (String filterString : excludeFilterStrings) 385 { 386 try 387 { 388 SearchFilter.createFilterFromString(filterString); 389 } 390 catch (DirectoryException de) 391 { 392 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER.get( 393 filterString, de.getMessageObject()); 394 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 395 } 396 } 397 398 for (String filterString : includeFilterStrings) 399 { 400 try 401 { 402 SearchFilter.createFilterFromString(filterString); 403 } 404 catch (DirectoryException de) 405 { 406 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER.get( 407 filterString, de.getMessageObject()); 408 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 409 } 410 } 411 412 if(backendID != null) 413 { 414 backend = DirectoryServer.getBackend(backendID); 415 if (backend == null) 416 { 417 Message message = ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID.get(); 418 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 419 } 420 else if (! backend.supportsLDIFImport()) 421 { 422 Message message = ERR_LDIFIMPORT_CANNOT_IMPORT.get(backendID); 423 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 424 } 425 // Make sure that if the "backendID" argument was provided, no include 426 // base was included, and the "append" ption was not provided, the 427 // "clearBackend" argument was also provided if there are more then one 428 // baseDNs for the backend being imported. 429 else if(!append && includeBranchStrings.isEmpty() && 430 backend.getBaseDNs().length > 1 && !clearBackend) 431 { 432 StringBuilder builder = new StringBuilder(); 433 for(DN dn : backend.getBaseDNs()) 434 { 435 builder.append(dn.toNormalizedString()); 436 builder.append(" "); 437 } 438 Message message = ERR_LDIFIMPORT_MISSING_CLEAR_BACKEND.get( 439 builder.toString(), typeClearBackend.getNameOrOID()); 440 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 441 } 442 } 443 else 444 { 445 // Find the backend that includes all the branches. 446 for(DN includeBranch : includeBranches) 447 { 448 Backend locatedBackend = DirectoryServer.getBackend(includeBranch); 449 if(locatedBackend != null) 450 { 451 if(backend == null) 452 { 453 backend = locatedBackend; 454 } 455 else if(backend != locatedBackend) 456 { 457 // The include branches span across multiple backends. 458 Message message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get( 459 includeBranch.toNormalizedString(), backend.getBackendID()); 460 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 461 message); 462 } 463 } 464 } 465 } 466 467 // Make sure the selected backend will handle all the include branches 468 defaultIncludeBranches = new ArrayList<DN>(backend.getBaseDNs().length); 469 for (DN dn : backend.getBaseDNs()) 470 { 471 defaultIncludeBranches.add(dn); 472 } 473 474 for(DN includeBranch : includeBranches) 475 { 476 if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches, 477 excludeBranches)) 478 { 479 Message message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get( 480 includeBranch.toNormalizedString(), backend.getBackendID()); 481 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 482 } 483 } 484 } 485 486 487 /** 488 * {@inheritDoc} 489 */ 490 public void interruptTask(TaskState interruptState, Message interruptReason) 491 { 492 if (TaskState.STOPPED_BY_ADMINISTRATOR.equals(interruptState) && 493 importConfig != null) 494 { 495 addLogMessage(TaskMessages.INFO_TASK_STOPPED_BY_ADMIN.get( 496 interruptReason)); 497 setTaskInterruptState(interruptState); 498 importConfig.cancel(); 499 } 500 } 501 502 503 /** 504 * {@inheritDoc} 505 */ 506 public boolean isInterruptable() 507 { 508 return true; 509 } 510 511 512 /** 513 * {@inheritDoc} 514 */ 515 protected TaskState runTask() 516 { 517 // See if there were any user-defined sets of include/exclude attributes or 518 // filters. If so, then process them. 519 HashSet<AttributeType> excludeAttributes = 520 new HashSet<AttributeType>(excludeAttributeStrings.size()); 521 for (String attrName : excludeAttributeStrings) 522 { 523 String lowerName = attrName.toLowerCase(); 524 AttributeType attrType = DirectoryServer.getAttributeType(lowerName); 525 if (attrType == null) 526 { 527 attrType = DirectoryServer.getDefaultAttributeType(attrName); 528 } 529 530 excludeAttributes.add(attrType); 531 } 532 533 HashSet<AttributeType> includeAttributes = 534 new HashSet<AttributeType>(includeAttributeStrings.size()); 535 for (String attrName : includeAttributeStrings) 536 { 537 String lowerName = attrName.toLowerCase(); 538 AttributeType attrType = DirectoryServer.getAttributeType(lowerName); 539 if (attrType == null) 540 { 541 attrType = DirectoryServer.getDefaultAttributeType(attrName); 542 } 543 544 includeAttributes.add(attrType); 545 } 546 547 ArrayList<SearchFilter> excludeFilters = 548 new ArrayList<SearchFilter>(excludeFilterStrings.size()); 549 for (String filterString : excludeFilterStrings) 550 { 551 try 552 { 553 excludeFilters.add(SearchFilter.createFilterFromString(filterString)); 554 } 555 catch (DirectoryException de) 556 { 557 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER.get( 558 filterString, de.getMessageObject()); 559 logError(message); 560 return TaskState.STOPPED_BY_ERROR; 561 } 562 } 563 564 ArrayList<SearchFilter> includeFilters = 565 new ArrayList<SearchFilter>(includeFilterStrings.size()); 566 for (String filterString : includeFilterStrings) 567 { 568 try 569 { 570 includeFilters.add(SearchFilter.createFilterFromString(filterString)); 571 } 572 catch (DirectoryException de) 573 { 574 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER.get( 575 filterString, de.getMessageObject()); 576 logError(message); 577 return TaskState.STOPPED_BY_ERROR; 578 } 579 } 580 581 582 // Get the backend into which the LDIF should be imported. 583 Backend backend = null; 584 ArrayList<DN> defaultIncludeBranches; 585 ArrayList<DN> excludeBranches = 586 new ArrayList<DN>(excludeBranchStrings.size()); 587 ArrayList<DN> includeBranches = 588 new ArrayList<DN>(includeBranchStrings.size()); 589 590 for (String s : includeBranchStrings) 591 { 592 DN includeBranch; 593 try 594 { 595 includeBranch = DN.decode(s); 596 } 597 catch (DirectoryException de) 598 { 599 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get( 600 s, de.getMessageObject()); 601 logError(message); 602 return TaskState.STOPPED_BY_ERROR; 603 } 604 catch (Exception e) 605 { 606 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get( 607 s, getExceptionMessage(e)); 608 logError(message); 609 return TaskState.STOPPED_BY_ERROR; 610 } 611 612 if(! includeBranches.contains(includeBranch)) 613 { 614 includeBranches.add(includeBranch); 615 } 616 } 617 618 if(backendID != null) 619 { 620 backend = DirectoryServer.getBackend(backendID); 621 622 if (backend == null) 623 { 624 Message message = ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID.get(); 625 logError(message); 626 return TaskState.STOPPED_BY_ERROR; 627 } 628 else if (! backend.supportsLDIFImport()) 629 { 630 Message message = ERR_LDIFIMPORT_CANNOT_IMPORT.get(backendID); 631 logError(message); 632 return TaskState.STOPPED_BY_ERROR; 633 } 634 // Make sure that if the "backendID" argument was provided, no include 635 // base was included, and the "append" ption was not provided, the 636 // "clearBackend" argument was also provided if there are more then one 637 // baseDNs for the backend being imported. 638 else if(!append && includeBranches.isEmpty() && 639 backend.getBaseDNs().length > 1 && !clearBackend) 640 { 641 StringBuilder builder = new StringBuilder(); 642 builder.append(backend.getBaseDNs()[0].toNormalizedString()); 643 for(int i = 1; i < backend.getBaseDNs().length; i++) 644 { 645 builder.append(" / "); 646 builder.append(backend.getBaseDNs()[i].toNormalizedString()); 647 } 648 Message message = ERR_LDIFIMPORT_MISSING_CLEAR_BACKEND.get( 649 builder.toString(), ATTR_IMPORT_CLEAR_BACKEND); 650 logError(message); 651 return TaskState.STOPPED_BY_ERROR; 652 } 653 } 654 else 655 { 656 // Find the backend that includes all the branches. 657 for(DN includeBranch : includeBranches) 658 { 659 Backend locatedBackend = DirectoryServer.getBackend(includeBranch); 660 if(locatedBackend != null) 661 { 662 if(backend == null) 663 { 664 backend = locatedBackend; 665 } 666 else if(backend != locatedBackend) 667 { 668 // The include branches span across multiple backends. 669 Message message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get( 670 includeBranch.toNormalizedString(), backend.getBackendID()); 671 logError(message); 672 return TaskState.STOPPED_BY_ERROR; 673 } 674 } 675 } 676 } 677 678 // Find backends with subordinate base DNs that should be excluded from the 679 // import. 680 681 defaultIncludeBranches = new ArrayList<DN>(backend.getBaseDNs().length); 682 for (DN dn : backend.getBaseDNs()) 683 { 684 defaultIncludeBranches.add(dn); 685 } 686 687 if (backend.getSubordinateBackends() != null) 688 { 689 for (Backend subBackend : backend.getSubordinateBackends()) 690 { 691 for (DN baseDN : subBackend.getBaseDNs()) 692 { 693 for (DN importBase : defaultIncludeBranches) 694 { 695 if (baseDN.isDescendantOf(importBase) && 696 (! baseDN.equals(importBase))) 697 { 698 if (! excludeBranches.contains(baseDN)) 699 { 700 excludeBranches.add(baseDN); 701 } 702 703 break; 704 } 705 } 706 } 707 } 708 } 709 710 for (String s : excludeBranchStrings) 711 { 712 DN excludeBranch; 713 try 714 { 715 excludeBranch = DN.decode(s); 716 } 717 catch (DirectoryException de) 718 { 719 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get( 720 s, de.getMessageObject()); 721 logError(message); 722 return TaskState.STOPPED_BY_ERROR; 723 } 724 catch (Exception e) 725 { 726 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get( 727 s, getExceptionMessage(e)); 728 logError(message); 729 return TaskState.STOPPED_BY_ERROR; 730 } 731 732 if (! excludeBranches.contains(excludeBranch)) 733 { 734 excludeBranches.add(excludeBranch); 735 } 736 } 737 738 if (includeBranchStrings.isEmpty()) 739 { 740 includeBranches = defaultIncludeBranches; 741 } 742 else 743 { 744 // Make sure the selected backend will handle all the include branches 745 for(DN includeBranch : includeBranches) 746 { 747 if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches, 748 excludeBranches)) 749 { 750 Message message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get( 751 includeBranch.toNormalizedString(), backend.getBackendID()); 752 logError(message); 753 return TaskState.STOPPED_BY_ERROR; 754 } 755 } 756 } 757 758 // Create the LDIF import configuration to use when reading the LDIF. 759 ArrayList<String> fileList = new ArrayList<String>(ldifFiles); 760 importConfig = new LDIFImportConfig(fileList); 761 importConfig.setAppendToExistingData(append); 762 importConfig.setReplaceExistingEntries(replaceExisting); 763 importConfig.setCompressed(isCompressed); 764 importConfig.setEncrypted(isEncrypted); 765 importConfig.setClearBackend(clearBackend); 766 importConfig.setExcludeAttributes(excludeAttributes); 767 importConfig.setExcludeBranches(excludeBranches); 768 importConfig.setExcludeFilters(excludeFilters); 769 importConfig.setIncludeAttributes(includeAttributes); 770 importConfig.setIncludeBranches(includeBranches); 771 importConfig.setIncludeFilters(includeFilters); 772 importConfig.setValidateSchema(!skipSchemaValidation); 773 774 // FIXME -- Should this be conditional? 775 importConfig.setInvokeImportPlugins(true); 776 777 if (rejectFile != null) 778 { 779 try 780 { 781 ExistingFileBehavior existingBehavior; 782 if (overwrite) 783 { 784 existingBehavior = ExistingFileBehavior.OVERWRITE; 785 } 786 else 787 { 788 existingBehavior = ExistingFileBehavior.APPEND; 789 } 790 791 importConfig.writeRejectedEntries(rejectFile, existingBehavior); 792 } 793 catch (Exception e) 794 { 795 Message message = ERR_LDIFIMPORT_CANNOT_OPEN_REJECTS_FILE.get( 796 rejectFile, getExceptionMessage(e)); 797 logError(message); 798 return TaskState.STOPPED_BY_ERROR; 799 } 800 } 801 802 if (skipFile != null) 803 { 804 try 805 { 806 ExistingFileBehavior existingBehavior; 807 if (overwrite) 808 { 809 existingBehavior = ExistingFileBehavior.OVERWRITE; 810 } 811 else 812 { 813 existingBehavior = ExistingFileBehavior.APPEND; 814 } 815 816 importConfig.writeRejectedEntries(skipFile, existingBehavior); 817 } 818 catch (Exception e) 819 { 820 Message message = ERR_LDIFIMPORT_CANNOT_OPEN_SKIP_FILE.get( 821 skipFile, getExceptionMessage(e)); 822 logError(message); 823 return TaskState.STOPPED_BY_ERROR; 824 } 825 } 826 827 // Get the set of base DNs for the backend as an array. 828 DN[] baseDNs = new DN[defaultIncludeBranches.size()]; 829 defaultIncludeBranches.toArray(baseDNs); 830 831 // Notify the task listeners that an import is going to start 832 // this must be done before disabling the backend to allow 833 // listeners to get access to the backend configuration 834 // and to take appropriate actions. 835 DirectoryServer.notifyImportBeginning(backend, importConfig); 836 837 // Disable the backend. 838 try 839 { 840 TaskUtils.disableBackend(backend.getBackendID()); 841 } 842 catch (DirectoryException e) 843 { 844 if (debugEnabled()) 845 { 846 TRACER.debugCaught(DebugLogLevel.ERROR, e); 847 } 848 849 logError(e.getMessageObject()); 850 return TaskState.STOPPED_BY_ERROR; 851 } 852 853 854 try 855 { 856 // Acquire an exclusive lock for the backend. 857 try 858 { 859 String lockFile = LockFileManager.getBackendLockFileName(backend); 860 StringBuilder failureReason = new StringBuilder(); 861 if (! LockFileManager.acquireExclusiveLock(lockFile, failureReason)) 862 { 863 Message message = ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND.get( 864 backend.getBackendID(), String.valueOf(failureReason)); 865 logError(message); 866 return TaskState.STOPPED_BY_ERROR; 867 } 868 } 869 catch (Exception e) 870 { 871 if (debugEnabled()) 872 { 873 TRACER.debugCaught(DebugLogLevel.ERROR, e); 874 } 875 876 Message message = ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND.get( 877 backend.getBackendID(), getExceptionMessage(e)); 878 logError(message); 879 return TaskState.STOPPED_BY_ERROR; 880 } 881 882 883 // Launch the import. 884 try 885 { 886 backend.importLDIF(importConfig); 887 } 888 catch (DirectoryException de) 889 { 890 if (debugEnabled()) 891 { 892 TRACER.debugCaught(DebugLogLevel.ERROR, de); 893 } 894 895 DirectoryServer.notifyImportEnded(backend, importConfig, false); 896 Message message = 897 ERR_LDIFIMPORT_ERROR_DURING_IMPORT.get(de.getMessageObject()); 898 logError(message); 899 return TaskState.STOPPED_BY_ERROR; 900 } 901 catch (Exception e) 902 { 903 if (debugEnabled()) 904 { 905 TRACER.debugCaught(DebugLogLevel.ERROR, e); 906 } 907 908 DirectoryServer.notifyImportEnded(backend, importConfig, false); 909 Message message = 910 ERR_LDIFIMPORT_ERROR_DURING_IMPORT.get(getExceptionMessage(e)); 911 logError(message); 912 return TaskState.STOPPED_BY_ERROR; 913 } 914 finally 915 { 916 // Release the exclusive lock on the backend. 917 try 918 { 919 String lockFile = LockFileManager.getBackendLockFileName(backend); 920 StringBuilder failureReason = new StringBuilder(); 921 if (! LockFileManager.releaseLock(lockFile, failureReason)) 922 { 923 Message message = WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND.get( 924 backend.getBackendID(), String.valueOf(failureReason)); 925 logError(message); 926 return TaskState.COMPLETED_WITH_ERRORS; 927 } 928 } 929 catch (Exception e) 930 { 931 if (debugEnabled()) 932 { 933 TRACER.debugCaught(DebugLogLevel.ERROR, e); 934 } 935 936 Message message = WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND.get( 937 backend.getBackendID(), getExceptionMessage(e)); 938 logError(message); 939 return TaskState.COMPLETED_WITH_ERRORS; 940 } 941 942 } 943 } 944 finally 945 { 946 // Enable the backend. 947 try 948 { 949 TaskUtils.enableBackend(backend.getBackendID()); 950 // It is necessary to retrieve the backend structure again 951 // because disabling and enabling it again may have resulted 952 // in a new backend being registered to the server. 953 backend = DirectoryServer.getBackend(backend.getBackendID()); 954 } 955 catch (DirectoryException e) 956 { 957 if (debugEnabled()) 958 { 959 TRACER.debugCaught(DebugLogLevel.ERROR, e); 960 } 961 962 logError(e.getMessageObject()); 963 return TaskState.STOPPED_BY_ERROR; 964 } 965 DirectoryServer.notifyImportEnded(backend, importConfig, true); 966 } 967 968 969 // Clean up after the import by closing the import config. 970 importConfig.close(); 971 return getFinalTaskState(); 972 } 973 }