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 2012-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools; 018 019import static org.opends.messages.ToolMessages.*; 020import static org.opends.server.config.ConfigConstants.*; 021import static org.opends.server.util.StaticUtils.*; 022 023import static com.forgerock.opendj.cli.ArgumentConstants.*; 024import static com.forgerock.opendj.cli.Utils.*; 025import static com.forgerock.opendj.cli.CommonArguments.*; 026 027import java.io.OutputStream; 028import java.io.PrintStream; 029import java.util.ArrayList; 030import java.util.HashSet; 031import java.util.List; 032import java.util.Set; 033 034import org.forgerock.i18n.slf4j.LocalizedLogger; 035import org.forgerock.opendj.config.server.ConfigException; 036import org.opends.server.admin.std.server.BackendCfg; 037import org.opends.server.api.Backend; 038import org.opends.server.api.Backend.BackendOperation; 039import org.opends.server.api.plugin.PluginType; 040import org.opends.server.core.CoreConfigManager; 041import org.opends.server.core.DirectoryServer; 042import org.opends.server.core.LockFileManager; 043import org.opends.server.extensions.ConfigFileHandler; 044import org.opends.server.loggers.DebugLogger; 045import org.opends.server.loggers.ErrorLogPublisher; 046import org.opends.server.loggers.ErrorLogger; 047import org.opends.server.loggers.JDKLogging; 048import org.opends.server.loggers.TextErrorLogPublisher; 049import org.opends.server.loggers.TextWriter; 050import org.opends.server.protocols.ldap.LDAPAttribute; 051import org.opends.server.tasks.ExportTask; 052import org.opends.server.tools.tasks.TaskTool; 053import org.forgerock.opendj.ldap.schema.AttributeType; 054import org.forgerock.opendj.ldap.DN; 055import org.opends.server.types.DirectoryException; 056import org.opends.server.types.ExistingFileBehavior; 057import org.opends.server.types.InitializationException; 058import org.opends.server.types.LDIFExportConfig; 059import org.opends.server.types.NullOutputStream; 060import org.opends.server.types.RawAttribute; 061import org.opends.server.types.SearchFilter; 062import org.opends.server.util.cli.LDAPConnectionArgumentParser; 063 064import com.forgerock.opendj.cli.Argument; 065import com.forgerock.opendj.cli.ArgumentException; 066import com.forgerock.opendj.cli.BooleanArgument; 067import com.forgerock.opendj.cli.ClientException; 068import com.forgerock.opendj.cli.IntegerArgument; 069import com.forgerock.opendj.cli.StringArgument; 070 071/** 072 * This program provides a utility that may be used to export the contents of a 073 * Directory Server backend to an LDIF file. Depending on the arguments given, 074 * this program will either perform the export directly as a process that 075 * runs separate from Directory Server; or by scheduling a task to perform the 076 * action within the Directory Server via the tasks interface. 077 */ 078public class ExportLDIF extends TaskTool { 079 080 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 081 082 /** 083 * The main method for ExportLDIF tool. 084 * 085 * @param args The command-line arguments provided to this program. 086 */ 087 public static void main(String[] args) 088 { 089 int retCode = mainExportLDIF(args, true, System.out, System.err); 090 091 if(retCode != 0) 092 { 093 System.exit(filterExitCode(retCode)); 094 } 095 } 096 097 /** 098 * Processes the command-line arguments and invokes the export process. 099 * 100 * @param args The command-line arguments provided to this program. 101 * 102 * @return The error code. 103 */ 104 public static int mainExportLDIF(String[] args) 105 { 106 return mainExportLDIF(args, true, System.out, System.err); 107 } 108 109 /** 110 * Processes the command-line arguments and invokes the export process. 111 * 112 * @param args The command-line arguments provided to this 113 * program. 114 * @param initializeServer Indicates whether to initialize the server. 115 * @param outStream The output stream to use for standard output, or 116 * {@code null} if standard output is not needed. 117 * @param errStream The output stream to use for standard error, or 118 * {@code null} if standard error is not needed. 119 * 120 * @return The error code. 121 */ 122 public static int mainExportLDIF(String[] args, boolean initializeServer, 123 OutputStream outStream, 124 OutputStream errStream) 125 { 126 ExportLDIF tool = new ExportLDIF(); 127 return tool.process(args, initializeServer, outStream, errStream); 128 } 129 130 /** Define the command-line arguments that may be used with this program. */ 131 private BooleanArgument appendToLDIF; 132 private BooleanArgument compressLDIF; 133 private BooleanArgument displayUsage; 134 private BooleanArgument encryptLDIF; 135 private BooleanArgument excludeOperationalAttrs; 136 private BooleanArgument signHash; 137 private IntegerArgument wrapColumn; 138 private StringArgument backendID; 139 private StringArgument configClass; 140 private StringArgument configFile; 141 private StringArgument excludeAttributeStrings; 142 private StringArgument excludeBranchStrings; 143 private StringArgument excludeFilterStrings; 144 private StringArgument includeAttributeStrings; 145 private StringArgument includeBranchStrings; 146 private StringArgument includeFilterStrings; 147 private StringArgument ldifFile; 148 149 private int process(String[] args, boolean initializeServer, 150 OutputStream outStream, OutputStream errStream) { 151 152 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 153 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 154 JDKLogging.disableLogging(); 155 156 // Create the command-line argument parser for use with this program. 157 LDAPConnectionArgumentParser argParser = 158 createArgParser("org.opends.server.tools.ExportLDIF", 159 INFO_LDIFEXPORT_TOOL_DESCRIPTION.get()); 160 argParser.setShortToolDescription(REF_SHORT_DESC_EXPORT_LDIF.get()); 161 162 163 // Initialize all the command-line argument types and register them with the 164 // parser. 165 try 166 { 167 configClass = 168 StringArgument.builder(OPTION_LONG_CONFIG_CLASS) 169 .shortIdentifier(OPTION_SHORT_CONFIG_CLASS) 170 .description(INFO_DESCRIPTION_CONFIG_CLASS.get()) 171 .hidden() 172 .required() 173 .defaultValue(ConfigFileHandler.class.getName()) 174 .valuePlaceholder(INFO_CONFIGCLASS_PLACEHOLDER.get()) 175 .buildAndAddToParser(argParser); 176 configFile = 177 StringArgument.builder("configFile") 178 .shortIdentifier('f') 179 .description(INFO_DESCRIPTION_CONFIG_FILE.get()) 180 .hidden() 181 .required() 182 .valuePlaceholder(INFO_CONFIGFILE_PLACEHOLDER.get()) 183 .buildAndAddToParser(argParser); 184 ldifFile = 185 StringArgument.builder(OPTION_LONG_LDIF_FILE) 186 .shortIdentifier(OPTION_SHORT_LDIF_FILE) 187 .description(INFO_LDIFEXPORT_DESCRIPTION_LDIF_FILE.get()) 188 .required() 189 .valuePlaceholder(INFO_LDIFFILE_PLACEHOLDER.get()) 190 .buildAndAddToParser(argParser); 191 appendToLDIF = 192 BooleanArgument.builder("appendToLDIF") 193 .shortIdentifier('a') 194 .description(INFO_LDIFEXPORT_DESCRIPTION_APPEND_TO_LDIF.get()) 195 .buildAndAddToParser(argParser); 196 backendID = 197 StringArgument.builder("backendID") 198 .shortIdentifier('n') 199 .description(INFO_LDIFEXPORT_DESCRIPTION_BACKEND_ID.get()) 200 .required() 201 .valuePlaceholder(INFO_BACKENDNAME_PLACEHOLDER.get()) 202 .buildAndAddToParser(argParser); 203 includeBranchStrings = 204 StringArgument.builder("includeBranch") 205 .shortIdentifier('b') 206 .description(INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_BRANCH.get()) 207 .multiValued() 208 .valuePlaceholder(INFO_BRANCH_DN_PLACEHOLDER.get()) 209 .buildAndAddToParser(argParser); 210 excludeBranchStrings = 211 StringArgument.builder("excludeBranch") 212 .shortIdentifier('B') 213 .description(INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_BRANCH.get()) 214 .multiValued() 215 .valuePlaceholder(INFO_BRANCH_DN_PLACEHOLDER.get()) 216 .buildAndAddToParser(argParser); 217 includeAttributeStrings = 218 StringArgument.builder("includeAttribute") 219 .shortIdentifier('i') 220 .description(INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_ATTRIBUTE.get()) 221 .multiValued() 222 .valuePlaceholder(INFO_ATTRIBUTE_PLACEHOLDER.get()) 223 .buildAndAddToParser(argParser); 224 excludeAttributeStrings = 225 StringArgument.builder("excludeAttribute") 226 .shortIdentifier('e') 227 .description(INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_ATTRIBUTE.get()) 228 .multiValued() 229 .valuePlaceholder(INFO_ATTRIBUTE_PLACEHOLDER.get()) 230 .buildAndAddToParser(argParser); 231 includeFilterStrings = 232 StringArgument.builder("includeFilter") 233 .shortIdentifier('I') 234 .description(INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_FILTER.get()) 235 .multiValued() 236 .valuePlaceholder(INFO_FILTER_PLACEHOLDER.get()) 237 .buildAndAddToParser(argParser); 238 excludeFilterStrings = 239 StringArgument.builder("excludeFilter") 240 .shortIdentifier('E') 241 .description(INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_FILTER.get()) 242 .multiValued() 243 .valuePlaceholder(INFO_FILTER_PLACEHOLDER.get()) 244 .buildAndAddToParser(argParser); 245 excludeOperationalAttrs = 246 BooleanArgument.builder("excludeOperational") 247 .shortIdentifier('O') 248 .description(INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_OPERATIONAL.get()) 249 .buildAndAddToParser(argParser); 250 wrapColumn = 251 IntegerArgument.builder("wrapColumn") 252 .description(INFO_LDIFEXPORT_DESCRIPTION_WRAP_COLUMN.get()) 253 .lowerBound(0) 254 .defaultValue(0) 255 .valuePlaceholder(INFO_WRAP_COLUMN_PLACEHOLDER.get()) 256 .buildAndAddToParser(argParser); 257 compressLDIF = 258 BooleanArgument.builder(OPTION_LONG_COMPRESS) 259 .shortIdentifier(OPTION_SHORT_COMPRESS) 260 .description(INFO_LDIFEXPORT_DESCRIPTION_COMPRESS_LDIF.get()) 261 .buildAndAddToParser(argParser); 262 encryptLDIF = 263 BooleanArgument.builder("encryptLDIF") 264 .shortIdentifier('y') 265 .description(INFO_LDIFEXPORT_DESCRIPTION_ENCRYPT_LDIF.get()) 266 .hidden() // See issue #27 267 .buildAndAddToParser(argParser); 268 signHash = 269 BooleanArgument.builder("signHash") 270 .shortIdentifier('s') 271 .description(INFO_LDIFEXPORT_DESCRIPTION_SIGN_HASH.get()) 272 .hidden() // See issue #28 273 .buildAndAddToParser(argParser); 274 275 displayUsage = showUsageArgument(); 276 argParser.addArgument(displayUsage); 277 argParser.setUsageArgument(displayUsage); 278 } 279 catch (ArgumentException ae) 280 { 281 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 282 return 1; 283 } 284 285 286 // Init the default values so that they can appear also on the usage. 287 argParser.getArguments().initArgumentsWithConfiguration(argParser); 288 289 // Parse the command-line arguments provided to this program. 290 try 291 { 292 argParser.parseArguments(args); 293 validateTaskArgs(); 294 } 295 catch (ArgumentException ae) 296 { 297 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 298 return 1; 299 } 300 catch (ClientException ce) 301 { 302 // No need to display the usage since the problem comes with a provided value. 303 printWrappedText(err, ce.getMessageObject()); 304 return 1; 305 } 306 307 308 // If we should just display usage or version information, 309 // then print it and exit. 310 if (argParser.usageOrVersionDisplayed()) 311 { 312 return 0; 313 } 314 315 // Checks the version - if upgrade required, the tool is unusable 316 try 317 { 318 checkVersion(); 319 } 320 catch (InitializationException e) 321 { 322 printWrappedText(err, e.getMessage()); 323 return 1; 324 } 325 326 return process(argParser, initializeServer, out, err); 327 } 328 329 /** {@inheritDoc} */ 330 @Override 331 public void addTaskAttributes(List<RawAttribute> attributes) 332 { 333 // Required attributes 334 attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_LDIF_FILE, ldifFile.getValue())); 335 attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_BACKEND_ID, backendID.getValue())); 336 337 // Optional attributes 338 addAttribute(attributes, ATTR_TASK_EXPORT_APPEND_TO_LDIF, appendToLDIF); 339 addAttribute(attributes, ATTR_TASK_EXPORT_COMPRESS_LDIF, compressLDIF); 340 addAttribute(attributes, ATTR_TASK_EXPORT_ENCRYPT_LDIF, encryptLDIF); 341 addAttribute(attributes, ATTR_TASK_EXPORT_SIGN_HASH, signHash); 342 addAttribute(attributes, ATTR_TASK_EXPORT_INCLUDE_ATTRIBUTE, includeAttributeStrings.getValues()); 343 addAttribute(attributes, ATTR_TASK_EXPORT_EXCLUDE_ATTRIBUTE, excludeAttributeStrings.getValues()); 344 addAttribute(attributes, ATTR_TASK_EXPORT_INCLUDE_FILTER, includeFilterStrings.getValues()); 345 addAttribute(attributes, ATTR_TASK_EXPORT_EXCLUDE_FILTER, excludeFilterStrings.getValues()); 346 addAttribute(attributes, ATTR_TASK_EXPORT_INCLUDE_BRANCH, includeBranchStrings.getValues()); 347 addAttribute(attributes, ATTR_TASK_EXPORT_EXCLUDE_BRANCH, excludeBranchStrings.getValues()); 348 addAttribute(attributes, ATTR_TASK_EXPORT_WRAP_COLUMN, wrapColumn); 349 350 if (excludeOperationalAttrs.isPresent()) 351 { 352 attributes.add( 353 new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_OPERATIONAL_ATTRIBUTES, "false")); 354 } 355 } 356 357 private void addAttribute(List<RawAttribute> attributes, String attrName, Argument arg) 358 { 359 if (arg.getValue() != null && !arg.getValue().equals(arg.getDefaultValue())) 360 { 361 attributes.add(new LDAPAttribute(attrName, arg.getValue())); 362 } 363 } 364 365 private void addAttribute(List<RawAttribute> attributes, String attrName, List<String> attrValues) 366 { 367 if (attrValues != null && !attrValues.isEmpty()) 368 { 369 attributes.add(new LDAPAttribute(attrName, attrValues)); 370 } 371 } 372 373 /** {@inheritDoc} */ 374 @Override 375 public String getTaskObjectclass() { 376 return "ds-task-export"; 377 } 378 379 /** {@inheritDoc} */ 380 @Override 381 public Class<?> getTaskClass() { 382 return ExportTask.class; 383 } 384 385 /** {@inheritDoc} */ 386 @Override 387 protected int processLocal(boolean initializeServer, 388 PrintStream out, 389 PrintStream err) { 390 391 // Perform the initial bootstrap of the Directory Server and process the 392 // configuration. 393 DirectoryServer directoryServer = DirectoryServer.getInstance(); 394 if (initializeServer) 395 { 396 try 397 { 398 DirectoryServer.bootstrapClient(); 399 DirectoryServer.initializeJMX(); 400 } 401 catch (Exception e) 402 { 403 printWrappedText(err, ERR_SERVER_BOOTSTRAP_ERROR.get(getExceptionMessage(e))); 404 return 1; 405 } 406 407 try 408 { 409 directoryServer.initializeConfiguration(configClass.getValue(), 410 configFile.getValue()); 411 } 412 catch (InitializationException ie) 413 { 414 printWrappedText(err, ERR_CANNOT_LOAD_CONFIG.get(ie.getMessage())); 415 return 1; 416 } 417 catch (Exception e) 418 { 419 printWrappedText(err, ERR_CANNOT_LOAD_CONFIG.get(getExceptionMessage(e))); 420 return 1; 421 } 422 423 424 425 // Initialize the Directory Server schema elements. 426 try 427 { 428 directoryServer.initializeSchema(); 429 } 430 catch (ConfigException | InitializationException e) 431 { 432 printWrappedText(err, ERR_CANNOT_LOAD_SCHEMA.get(e.getMessage())); 433 return 1; 434 } 435 catch (Exception e) 436 { 437 printWrappedText(err, ERR_CANNOT_LOAD_SCHEMA.get(getExceptionMessage(e))); 438 return 1; 439 } 440 441 442 // Initialize the Directory Server core configuration. 443 try 444 { 445 CoreConfigManager coreConfigManager = new CoreConfigManager(directoryServer.getServerContext()); 446 coreConfigManager.initializeCoreConfig(); 447 } 448 catch (ConfigException | InitializationException e) 449 { 450 printWrappedText(err, ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(e.getMessage())); 451 return 1; 452 } 453 catch (Exception e) 454 { 455 printWrappedText(err, ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(getExceptionMessage(e))); 456 return 1; 457 } 458 459 460 // Initialize the Directory Server crypto manager. 461 try 462 { 463 directoryServer.initializeCryptoManager(); 464 } 465 catch (ConfigException | InitializationException e) 466 { 467 printWrappedText(err, ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(e.getMessage())); 468 return 1; 469 } 470 catch (Exception e) 471 { 472 printWrappedText(err, ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(getExceptionMessage(e))); 473 return 1; 474 } 475 476 477 try 478 { 479 ErrorLogPublisher errorLogPublisher = 480 TextErrorLogPublisher.getToolStartupTextErrorPublisher( 481 new TextWriter.STREAM(out)); 482 ErrorLogger.getInstance().addLogPublisher(errorLogPublisher); 483 484 DebugLogger.getInstance().addPublisherIfRequired(new TextWriter.STREAM(out)); 485 } 486 catch(Exception e) 487 { 488 err.println("Error installing the custom error logger: " + 489 stackTraceToSingleLineString(e)); 490 } 491 492 493 494 // Make sure that the Directory Server plugin initialization is performed. 495 try 496 { 497 HashSet<PluginType> pluginTypes = new HashSet<>(1); 498 pluginTypes.add(PluginType.LDIF_EXPORT); 499 directoryServer.initializePlugins(pluginTypes); 500 } 501 catch (ConfigException | InitializationException e) 502 { 503 printWrappedText(err, ERR_LDIFEXPORT_CANNOT_INITIALIZE_PLUGINS.get(e.getMessage())); 504 return 1; 505 } 506 catch (Exception e) 507 { 508 printWrappedText(err, ERR_LDIFEXPORT_CANNOT_INITIALIZE_PLUGINS.get(getExceptionMessage(e))); 509 return 1; 510 } 511 } 512 513 514 // See if there were any user-defined sets of include/exclude attributes or 515 // filters. If so, then process them. 516 Set<AttributeType> excludeAttributes = toAttributeTypes(excludeAttributeStrings); 517 Set<AttributeType> includeAttributes = toAttributeTypes(includeAttributeStrings); 518 519 ArrayList<SearchFilter> excludeFilters; 520 if (excludeFilterStrings == null) 521 { 522 excludeFilters = null; 523 } 524 else 525 { 526 excludeFilters = new ArrayList<>(); 527 for (String filterString : excludeFilterStrings.getValues()) 528 { 529 try 530 { 531 excludeFilters.add(SearchFilter.createFilterFromString(filterString)); 532 } 533 catch (DirectoryException de) 534 { 535 logger.error(ERR_LDIFEXPORT_CANNOT_PARSE_EXCLUDE_FILTER, filterString, de.getMessageObject()); 536 return 1; 537 } 538 catch (Exception e) 539 { 540 logger.error(ERR_LDIFEXPORT_CANNOT_PARSE_EXCLUDE_FILTER, filterString, getExceptionMessage(e)); 541 return 1; 542 } 543 } 544 } 545 546 ArrayList<SearchFilter> includeFilters; 547 if (includeFilterStrings == null) 548 { 549 includeFilters = null; 550 } 551 else 552 { 553 includeFilters = new ArrayList<>(); 554 for (String filterString : includeFilterStrings.getValues()) 555 { 556 try 557 { 558 includeFilters.add(SearchFilter.createFilterFromString(filterString)); 559 } 560 catch (DirectoryException de) 561 { 562 logger.error(ERR_LDIFEXPORT_CANNOT_PARSE_INCLUDE_FILTER, filterString, de.getMessageObject()); 563 return 1; 564 } 565 catch (Exception e) 566 { 567 logger.error(ERR_LDIFEXPORT_CANNOT_PARSE_INCLUDE_FILTER, filterString, getExceptionMessage(e)); 568 return 1; 569 } 570 } 571 } 572 573 574 // Get information about the backends defined in the server. Iterate 575 // through them, finding the one backend that should be used for the export, 576 // and also finding backends with subordinate base DNs that should be 577 // excluded from the export. 578 Backend backend = null; 579 List<DN> baseDNList = null; 580 List<DN> defaultIncludeBranches = null; 581 ArrayList<DN> excludeBranches = null; 582 583 ArrayList<Backend> backendList = new ArrayList<>(); 584 ArrayList<BackendCfg> entryList = new ArrayList<>(); 585 ArrayList<List<DN>> dnList = new ArrayList<>(); 586 BackendToolUtils.getBackends(backendList, entryList, dnList); 587 588 int numBackends = backendList.size(); 589 for (int i=0; i < numBackends; i++) 590 { 591 Backend b = backendList.get(i); 592 if (! backendID.getValue().equals(b.getBackendID())) 593 { 594 continue; 595 } 596 597 if (backend == null) 598 { 599 backend = b; 600 baseDNList = dnList.get(i); 601 defaultIncludeBranches = dnList.get(i); 602 } 603 else 604 { 605 logger.error(ERR_LDIFEXPORT_MULTIPLE_BACKENDS_FOR_ID, backendID.getValue()); 606 return 1; 607 } 608 } 609 610 if (backend == null) 611 { 612 logger.error(ERR_LDIFEXPORT_NO_BACKENDS_FOR_ID, backendID.getValue()); 613 return 1; 614 } 615 else if (!backend.supports(BackendOperation.RESTORE)) 616 { 617 logger.error(ERR_LDIFEXPORT_CANNOT_EXPORT_BACKEND, backendID.getValue()); 618 return 1; 619 } 620 621 if (excludeBranchStrings.isPresent()) 622 { 623 excludeBranches = new ArrayList<>(); 624 for (String s : excludeBranchStrings.getValues()) 625 { 626 DN excludeBranch; 627 try 628 { 629 excludeBranch = DN.valueOf(s); 630 } 631 catch (Exception e) 632 { 633 logger.error(ERR_LDIFEXPORT_CANNOT_DECODE_EXCLUDE_BASE, s, getExceptionMessage(e)); 634 return 1; 635 } 636 637 if (! excludeBranches.contains(excludeBranch)) 638 { 639 excludeBranches.add(excludeBranch); 640 } 641 } 642 } 643 644 645 List<DN> includeBranches; 646 if (includeBranchStrings.isPresent()) 647 { 648 includeBranches = new ArrayList<>(); 649 for (String s : includeBranchStrings.getValues()) 650 { 651 DN includeBranch; 652 try 653 { 654 includeBranch = DN.valueOf(s); 655 } 656 catch (Exception e) 657 { 658 logger.error(ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE, s, getExceptionMessage(e)); 659 return 1; 660 } 661 662 if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches, 663 excludeBranches)) 664 { 665 logger.error(ERR_LDIFEXPORT_INVALID_INCLUDE_BASE, s, backendID.getValue()); 666 return 1; 667 } 668 669 includeBranches.add(includeBranch); 670 } 671 } 672 else 673 { 674 includeBranches = defaultIncludeBranches; 675 } 676 677 678 // Create the LDIF export configuration to use when reading the LDIF. 679 ExistingFileBehavior existingBehavior; 680 if (appendToLDIF.isPresent()) 681 { 682 existingBehavior = ExistingFileBehavior.APPEND; 683 } 684 else 685 { 686 existingBehavior = ExistingFileBehavior.OVERWRITE; 687 } 688 689 LDIFExportConfig exportConfig = new LDIFExportConfig(ldifFile.getValue(), 690 existingBehavior); 691 exportConfig.setCompressData(compressLDIF.isPresent()); 692 exportConfig.setEncryptData(encryptLDIF.isPresent()); 693 exportConfig.setExcludeAttributes(excludeAttributes); 694 exportConfig.setExcludeBranches(excludeBranches); 695 exportConfig.setExcludeFilters(excludeFilters); 696 exportConfig.setIncludeAttributes(includeAttributes); 697 exportConfig.setIncludeBranches(includeBranches); 698 exportConfig.setIncludeFilters(includeFilters); 699 exportConfig.setSignHash(signHash.isPresent()); 700 exportConfig.setIncludeOperationalAttributes( 701 !excludeOperationalAttrs.isPresent()); 702 703 // FIXME -- Should this be conditional? 704 exportConfig.setInvokeExportPlugins(true); 705 706 try 707 { 708 exportConfig.setWrapColumn(wrapColumn.getIntValue()); 709 } 710 catch (ArgumentException ae) 711 { 712 logger.error(ERR_LDIFEXPORT_CANNOT_DECODE_WRAP_COLUMN_AS_INTEGER, wrapColumn.getValue()); 713 return 1; 714 } 715 716 717 // Get the set of base DNs for the backend as an array. 718 DN[] baseDNs = new DN[baseDNList.size()]; 719 baseDNList.toArray(baseDNs); 720 721 722 // Acquire a shared lock for the backend. 723 try 724 { 725 String lockFile = LockFileManager.getBackendLockFileName(backend); 726 StringBuilder failureReason = new StringBuilder(); 727 if (! LockFileManager.acquireSharedLock(lockFile, failureReason)) 728 { 729 logger.error(ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND, backend.getBackendID(), failureReason); 730 return 1; 731 } 732 } 733 catch (Exception e) 734 { 735 logger.error(ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND, backend.getBackendID(), getExceptionMessage(e)); 736 return 1; 737 } 738 739 boolean errorOccurred = false; 740 741 // Launch the export. 742 try 743 { 744 backend.exportLDIF(exportConfig); 745 } 746 catch (DirectoryException de) 747 { 748 logger.error(ERR_LDIFEXPORT_ERROR_DURING_EXPORT, de.getMessageObject()); 749 errorOccurred = true; 750 } 751 catch (Exception e) 752 { 753 logger.error(ERR_LDIFEXPORT_ERROR_DURING_EXPORT, getExceptionMessage(e)); 754 errorOccurred = true; 755 } 756 757 758 // Release the shared lock on the backend. 759 try 760 { 761 String lockFile = LockFileManager.getBackendLockFileName(backend); 762 StringBuilder failureReason = new StringBuilder(); 763 if (! LockFileManager.releaseLock(lockFile, failureReason)) 764 { 765 logger.warn(WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND, backend.getBackendID(), failureReason); 766 } 767 } 768 catch (Exception e) 769 { 770 logger.warn(WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND, backend.getBackendID(), getExceptionMessage(e)); 771 } 772 773 774 // Clean up after the export by closing the export config. 775 exportConfig.close(); 776 return !errorOccurred ? 0 : 1; 777 } 778 779 private Set<AttributeType> toAttributeTypes(StringArgument attributeArg) 780 { 781 if (attributeArg == null) 782 { 783 return null; 784 } 785 786 Set<AttributeType> results = new HashSet<>(); 787 for (String attrName : attributeArg.getValues()) 788 { 789 results.add(DirectoryServer.getAttributeType(attrName)); 790 } 791 return results; 792 } 793 794 /** {@inheritDoc} */ 795 @Override 796 public String getTaskId() { 797 // NYI. 798 return null; 799 } 800}