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