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-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-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.File; 037import java.io.OutputStream; 038import java.io.PrintStream; 039import java.util.ArrayList; 040import java.util.HashSet; 041import java.util.List; 042import java.util.Random; 043import java.util.Set; 044 045import org.forgerock.i18n.LocalizableMessage; 046import org.forgerock.i18n.slf4j.LocalizedLogger; 047import org.forgerock.opendj.config.server.ConfigException; 048import org.forgerock.opendj.ldap.ResultCode; 049import org.opends.server.admin.std.server.BackendCfg; 050import org.opends.server.api.Backend; 051import org.opends.server.api.Backend.BackendOperation; 052import org.opends.server.api.plugin.PluginType; 053import org.opends.server.core.CoreConfigManager; 054import org.opends.server.core.DirectoryServer; 055import org.opends.server.core.LockFileManager; 056import org.opends.server.core.PluginConfigManager; 057import org.opends.server.extensions.ConfigFileHandler; 058import org.opends.server.loggers.ErrorLogPublisher; 059import org.opends.server.loggers.ErrorLogger; 060import org.opends.server.loggers.JDKLogging; 061import org.opends.server.loggers.TextErrorLogPublisher; 062import org.opends.server.loggers.TextWriter; 063import org.opends.server.protocols.ldap.LDAPAttribute; 064import org.opends.server.tasks.ImportTask; 065import org.opends.server.tools.makeldif.TemplateFile; 066import org.opends.server.tools.tasks.TaskTool; 067import org.opends.server.types.AttributeType; 068import org.opends.server.types.DN; 069import org.opends.server.types.DirectoryException; 070import org.opends.server.types.ExistingFileBehavior; 071import org.opends.server.types.InitializationException; 072import org.opends.server.types.LDIFImportConfig; 073import org.opends.server.types.LDIFImportResult; 074import org.opends.server.types.NullOutputStream; 075import org.opends.server.types.RawAttribute; 076import org.opends.server.types.SearchFilter; 077import org.opends.server.util.args.LDAPConnectionArgumentParser; 078 079import com.forgerock.opendj.cli.Argument; 080import com.forgerock.opendj.cli.ArgumentException; 081import com.forgerock.opendj.cli.BooleanArgument; 082import com.forgerock.opendj.cli.ClientException; 083import com.forgerock.opendj.cli.CommonArguments; 084import com.forgerock.opendj.cli.IntegerArgument; 085import com.forgerock.opendj.cli.StringArgument; 086 087/** 088 * This program provides a utility that may be used to import the contents of an 089 * LDIF file into a Directory Server backend. This will be a process that is 090 * intended to run separate from Directory Server and not internally within the 091 * server process (e.g., via the tasks interface). 092 */ 093public class ImportLDIF extends TaskTool { 094 095 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 096 097 /** 098 * The buffer size that should be used when reading data from LDIF. 099 */ 100 public static final int LDIF_BUFFER_SIZE = 1048576; 101 102 103 /** 104 * The main method for ImportLDIF tool. 105 * 106 * @param args The command-line arguments provided to this program. 107 */ 108 public static void main(String[] args) 109 { 110 int retCode = mainImportLDIF(args, true, System.out, System.err); 111 112 if(retCode != 0) 113 { 114 System.exit(filterExitCode(retCode)); 115 } 116 } 117 118 /** 119 * Processes the command-line arguments and invokes the import process. 120 * 121 * @param args The command-line arguments provided to this program. 122 * @return The error code. 123 */ 124 public static int mainImportLDIF(String[] args) 125 { 126 return mainImportLDIF(args, true, System.out, System.err); 127 } 128 129 /** 130 * Processes the command-line arguments and invokes the import process. 131 * 132 * @param args The command-line arguments provided to this 133 * program. 134 * @param initializeServer Indicates whether to initialize the server. 135 * @param outStream The output stream to use for standard output, or 136 * {@code null} if standard output is not needed. 137 * @param errStream The output stream to use for standard error, or 138 * {@code null} if standard error is not needed. 139 * 140 * @return The error code. 141 */ 142 public static int mainImportLDIF(String[] args, boolean initializeServer, 143 OutputStream outStream, 144 OutputStream errStream) 145 { 146 ImportLDIF tool = new ImportLDIF(); 147 return tool.process(args, initializeServer, outStream, errStream); 148 } 149 150 /** Define the command-line arguments that may be used with this program. */ 151 private BooleanArgument countRejects; 152 private BooleanArgument displayUsage; 153 private BooleanArgument isCompressed; 154 private BooleanArgument isEncrypted; 155 private BooleanArgument overwrite; 156 private BooleanArgument quietMode; 157 private BooleanArgument skipSchemaValidation; 158 private BooleanArgument clearBackend; 159 private IntegerArgument randomSeed; 160 private StringArgument backendID; 161 private StringArgument configClass; 162 private StringArgument configFile; 163 private StringArgument excludeAttributeStrings; 164 private StringArgument excludeBranchStrings; 165 private StringArgument excludeFilterStrings; 166 private StringArgument includeAttributeStrings; 167 private StringArgument includeBranchStrings; 168 private StringArgument includeFilterStrings; 169 private StringArgument ldifFiles; 170 private StringArgument rejectFile; 171 private StringArgument skipFile; 172 private StringArgument templateFile; 173 private BooleanArgument skipDNValidation; 174 private IntegerArgument threadCount; 175 private StringArgument tmpDirectory; 176 177 private int process(String[] args, boolean initializeServer, 178 OutputStream outStream, OutputStream errStream) { 179 180 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 181 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 182 JDKLogging.disableLogging(); 183 184 // FIXME -- Need to add a mechanism for verifying the file signature. 185 186 187 // Create the command-line argument parser for use with this program. 188 LDAPConnectionArgumentParser argParser = 189 createArgParser("org.opends.server.tools.ImportLDIF", INFO_LDIFIMPORT_TOOL_DESCRIPTION.get()); 190 argParser.setShortToolDescription(REF_SHORT_DESC_IMPORT_LDIF.get()); 191 192 // Initialize all the command-line argument types and register them with the 193 // parser. 194 try 195 { 196 createArguments(argParser); 197 } 198 catch (ArgumentException ae) 199 { 200 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 201 return 1; 202 } 203 204 // Init the default values so that they can appear also on the usage. 205 try 206 { 207 argParser.getArguments().initArgumentsWithConfiguration(); 208 } 209 catch (ConfigException ce) 210 { 211 // Ignore. 212 } 213 214 // Parse the command-line arguments provided to this program. 215 try 216 { 217 argParser.parseArguments(args); 218 validateTaskArgs(); 219 } 220 catch (ArgumentException ae) 221 { 222 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 223 return 1; 224 } 225 catch (ClientException ce) 226 { 227 // No need to display the usage since the problem comes with a provided value. 228 printWrappedText(err, ce.getMessageObject()); 229 return 1; 230 } 231 232 233 if (argParser.usageOrVersionDisplayed()) 234 { 235 return 0; 236 } 237 238 239 // Make sure that either the "ldifFile" argument or the "templateFile" 240 // argument was provided, but not both. 241 if (ldifFiles.isPresent()) 242 { 243 if (templateFile.isPresent()) 244 { 245 printWrappedText(err, 246 ERR_LDIFIMPORT_CONFLICTING_OPTIONS.get(ldifFiles.getLongIdentifier(), templateFile.getLongIdentifier())); 247 return 1; 248 } 249 } 250 else if (! templateFile.isPresent()) 251 { 252 argParser.displayMessageAndUsageReference(err, ERR_LDIFIMPORT_MISSING_REQUIRED_ARGUMENT.get( 253 ldifFiles.getLongIdentifier(), templateFile.getLongIdentifier())); 254 return 1; 255 } 256 257 // Make sure that either the "includeBranchStrings" argument or the 258 // "backendID" argument was provided. 259 if(!includeBranchStrings.isPresent() && !backendID.isPresent()) 260 { 261 argParser.displayMessageAndUsageReference(err, ERR_LDIFIMPORT_MISSING_BACKEND_ARGUMENT.get( 262 includeBranchStrings.getLongIdentifier(), backendID.getLongIdentifier())); 263 return 1; 264 } 265 266 // Count rejects option requires the ability to return result codes 267 // which are potentially greater than 1. This is not supported by 268 // the task framework. 269 if (countRejects.isPresent() && argParser.connectionArgumentsPresent()) 270 { 271 argParser.displayMessageAndUsageReference(err, ERR_LDIFIMPORT_COUNT_REJECTS_REQUIRES_OFFLINE.get( 272 countRejects.getLongIdentifier())); 273 return 1; 274 } 275 276 // Don't write non-error messages to console if quite 277 if (quietMode.isPresent()) { 278 out = new PrintStream(NullOutputStream.instance()); 279 } 280 281 // Checks the version - if upgrade required, the tool is unusable 282 try 283 { 284 checkVersion(); 285 } 286 catch (InitializationException e) 287 { 288 printWrappedText(err, e.getMessage()); 289 return 1; 290 } 291 292 return process(argParser, initializeServer, out, err); 293 } 294 295 private void createArguments(LDAPConnectionArgumentParser argParser) throws ArgumentException 296 { 297 configClass = 298 new StringArgument("configclass", OPTION_SHORT_CONFIG_CLASS, 299 OPTION_LONG_CONFIG_CLASS, true, false, 300 true, INFO_CONFIGCLASS_PLACEHOLDER.get(), 301 ConfigFileHandler.class.getName(), null, 302 INFO_DESCRIPTION_CONFIG_CLASS.get()); 303 configClass.setHidden(true); 304 argParser.addArgument(configClass); 305 306 307 configFile = 308 new StringArgument("configfile", 'f', "configFile", true, false, 309 true, INFO_CONFIGFILE_PLACEHOLDER.get(), null, 310 null, 311 INFO_DESCRIPTION_CONFIG_FILE.get()); 312 configFile.setHidden(true); 313 argParser.addArgument(configFile); 314 315 316 ldifFiles = 317 new StringArgument("ldiffile", OPTION_SHORT_LDIF_FILE, 318 OPTION_LONG_LDIF_FILE, false, true, true, 319 INFO_LDIFFILE_PLACEHOLDER.get(), null, null, 320 INFO_LDIFIMPORT_DESCRIPTION_LDIF_FILE.get()); 321 argParser.addArgument(ldifFiles); 322 323 324 templateFile = 325 new StringArgument("templatefile", 'A', "templateFile", false, false, 326 true, INFO_TEMPLATE_FILE_PLACEHOLDER.get(), null, 327 null, 328 INFO_LDIFIMPORT_DESCRIPTION_TEMPLATE_FILE.get()); 329 argParser.addArgument(templateFile); 330 331 backendID = 332 new StringArgument("backendid", 'n', "backendID", false, false, true, 333 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null, 334 INFO_LDIFIMPORT_DESCRIPTION_BACKEND_ID.get()); 335 argParser.addArgument(backendID); 336 337 clearBackend = 338 new BooleanArgument("clearbackend", 'F', "clearBackend", 339 INFO_LDIFIMPORT_DESCRIPTION_CLEAR_BACKEND.get()); 340 argParser.addArgument(clearBackend); 341 342 343 includeBranchStrings = 344 new StringArgument("includebranch", 'b', "includeBranch", false, 345 true, true, INFO_BRANCH_DN_PLACEHOLDER.get(), 346 null, null, 347 INFO_LDIFIMPORT_DESCRIPTION_INCLUDE_BRANCH.get()); 348 argParser.addArgument(includeBranchStrings); 349 350 351 excludeBranchStrings = 352 new StringArgument("excludebranch", 'B', "excludeBranch", false, 353 true, true, INFO_BRANCH_DN_PLACEHOLDER.get(), 354 null, null, 355 INFO_LDIFIMPORT_DESCRIPTION_EXCLUDE_BRANCH.get()); 356 argParser.addArgument(excludeBranchStrings); 357 358 359 includeAttributeStrings = 360 new StringArgument( 361 "includeattribute", 'i', "includeAttribute", 362 false, true, true, INFO_ATTRIBUTE_PLACEHOLDER.get(), null, 363 null, 364 INFO_LDIFIMPORT_DESCRIPTION_INCLUDE_ATTRIBUTE.get()); 365 argParser.addArgument(includeAttributeStrings); 366 367 368 excludeAttributeStrings = 369 new StringArgument( 370 "excludeattribute", 'e', "excludeAttribute", 371 false, true, true, INFO_ATTRIBUTE_PLACEHOLDER.get(), null, 372 null, 373 INFO_LDIFIMPORT_DESCRIPTION_EXCLUDE_ATTRIBUTE.get()); 374 argParser.addArgument(excludeAttributeStrings); 375 376 377 includeFilterStrings = 378 new StringArgument( 379 "includefilter", 'I', "includeFilter", 380 false, true, true, INFO_FILTER_PLACEHOLDER.get(), null, null, 381 INFO_LDIFIMPORT_DESCRIPTION_INCLUDE_FILTER.get()); 382 argParser.addArgument(includeFilterStrings); 383 384 385 excludeFilterStrings = 386 new StringArgument("excludefilter", 'E', "excludeFilter", 387 false, true, true, INFO_FILTER_PLACEHOLDER.get(), 388 null, null, 389 INFO_LDIFIMPORT_DESCRIPTION_EXCLUDE_FILTER.get()); 390 argParser.addArgument(excludeFilterStrings); 391 392 393 rejectFile = 394 new StringArgument("rejectfile", 'R', "rejectFile", false, false, 395 true, INFO_REJECT_FILE_PLACEHOLDER.get(), null, 396 null, 397 INFO_LDIFIMPORT_DESCRIPTION_REJECT_FILE.get()); 398 argParser.addArgument(rejectFile); 399 400 401 skipFile = 402 new StringArgument("skipfile", null, "skipFile", false, false, 403 true, INFO_SKIP_FILE_PLACEHOLDER.get(), null, 404 null, 405 INFO_LDIFIMPORT_DESCRIPTION_SKIP_FILE.get()); 406 argParser.addArgument(skipFile); 407 408 409 overwrite = 410 new BooleanArgument("overwrite", 'O', "overwrite", 411 INFO_LDIFIMPORT_DESCRIPTION_OVERWRITE.get()); 412 argParser.addArgument(overwrite); 413 414 415 randomSeed = 416 new IntegerArgument("randomseed", OPTION_SHORT_RANDOM_SEED, 417 OPTION_LONG_RANDOM_SEED, false, false, 418 true, INFO_SEED_PLACEHOLDER.get(), 419 0, null, false, 0, false, 0, 420 INFO_LDIFIMPORT_DESCRIPTION_RANDOM_SEED.get()); 421 argParser.addArgument(randomSeed); 422 423 424 skipSchemaValidation = 425 new BooleanArgument("skipschema", 'S', "skipSchemaValidation", 426 INFO_LDIFIMPORT_DESCRIPTION_SKIP_SCHEMA_VALIDATION.get()); 427 argParser.addArgument(skipSchemaValidation); 428 429 430 skipDNValidation = 431 new BooleanArgument("skipDNValidation", null, "skipDNValidation", 432 INFO_LDIFIMPORT_DESCRIPTION_DN_VALIDATION.get()); 433 argParser.addArgument(skipDNValidation); 434 435 436 threadCount = new IntegerArgument("threadCount", null, "threadCount", 437 false, false, true, 438 INFO_LDIFIMPORT_THREAD_COUNT_PLACEHOLDER.get(), 439 0, null, 440 true, 1, true, Integer.MAX_VALUE, 441 INFO_LDIFIMPORT_DESCRIPTION_THREAD_COUNT.get()); 442 argParser.addArgument(threadCount); 443 444 tmpDirectory = 445 new StringArgument("tmpdirectory", null, "tmpdirectory", false, 446 false, true, INFO_LDIFIMPORT_TEMP_DIR_PLACEHOLDER.get(), 447 "import-tmp", 448 null, INFO_LDIFIMPORT_DESCRIPTION_TEMP_DIRECTORY.get()); 449 argParser.addArgument(tmpDirectory); 450 451 452 countRejects = 453 new BooleanArgument("countrejects", null, "countRejects", 454 INFO_LDIFIMPORT_DESCRIPTION_COUNT_REJECTS.get()); 455 argParser.addArgument(countRejects); 456 457 458 isCompressed = 459 new BooleanArgument("iscompressed", 'c', "isCompressed", 460 INFO_LDIFIMPORT_DESCRIPTION_IS_COMPRESSED.get()); 461 argParser.addArgument(isCompressed); 462 463 464 isEncrypted = 465 new BooleanArgument("isencrypted", 'y', "isEncrypted", 466 INFO_LDIFIMPORT_DESCRIPTION_IS_ENCRYPTED.get()); 467 isEncrypted.setHidden(true); //See issue #27 468 argParser.addArgument(isEncrypted); 469 470 471 quietMode = new BooleanArgument("quietmode", OPTION_SHORT_QUIET, 472 OPTION_LONG_QUIET, 473 INFO_LDIFIMPORT_DESCRIPTION_QUIET.get()); 474 argParser.addArgument(quietMode); 475 476 477 displayUsage = CommonArguments.getShowUsage(); 478 argParser.addArgument(displayUsage); 479 argParser.setUsageArgument(displayUsage); 480 } 481 482 @Override 483 public void addTaskAttributes(List<RawAttribute> attributes) 484 { 485 // Required attributes 486 addAttribute(attributes, ATTR_IMPORT_LDIF_FILE, ldifFiles.getValues()); 487 addAttribute(attributes, ATTR_IMPORT_TEMPLATE_FILE, templateFile.getValue()); 488 addAttribute(attributes, ATTR_IMPORT_RANDOM_SEED, randomSeed.getValue()); 489 addAttribute(attributes, ATTR_IMPORT_THREAD_COUNT, threadCount.getValue()); 490 491 // Optional attributes 492 addAttribute2(attributes, ATTR_IMPORT_BACKEND_ID, backendID); 493 addAttribute(attributes, ATTR_IMPORT_INCLUDE_ATTRIBUTE, includeAttributeStrings.getValues()); 494 addAttribute(attributes, ATTR_IMPORT_EXCLUDE_ATTRIBUTE, excludeAttributeStrings.getValues()); 495 addAttribute(attributes, ATTR_IMPORT_INCLUDE_FILTER, includeFilterStrings.getValues()); 496 addAttribute(attributes, ATTR_IMPORT_EXCLUDE_FILTER, excludeFilterStrings.getValues()); 497 addAttribute(attributes, ATTR_IMPORT_INCLUDE_BRANCH, includeBranchStrings.getValues()); 498 addAttribute(attributes, ATTR_IMPORT_EXCLUDE_BRANCH, excludeBranchStrings.getValues()); 499 addAttribute2(attributes, ATTR_IMPORT_REJECT_FILE, rejectFile); 500 addAttribute2(attributes, ATTR_IMPORT_SKIP_FILE, skipFile); 501 addAttribute2(attributes, ATTR_IMPORT_OVERWRITE, overwrite); 502 addAttribute2(attributes, ATTR_IMPORT_SKIP_SCHEMA_VALIDATION, skipSchemaValidation); 503 addAttribute2(attributes, ATTR_IMPORT_TMP_DIRECTORY, tmpDirectory); 504 addAttribute2(attributes, ATTR_IMPORT_SKIP_DN_VALIDATION, skipDNValidation); 505 addAttribute2(attributes, ATTR_IMPORT_IS_COMPRESSED, isCompressed); 506 addAttribute2(attributes, ATTR_IMPORT_IS_ENCRYPTED, isEncrypted); 507 addAttribute2(attributes, ATTR_IMPORT_CLEAR_BACKEND, clearBackend); 508 } 509 510 private void addAttribute(List<RawAttribute> attributes, String attrName, String value) 511 { 512 if (value != null) 513 { 514 attributes.add(new LDAPAttribute(attrName, value)); 515 } 516 } 517 518 private void addAttribute2(List<RawAttribute> attributes, String attrName, Argument arg) 519 { 520 final String value = arg.getValue(); 521 if (value != null && !value.equals(arg.getDefaultValue())) 522 { 523 attributes.add(new LDAPAttribute(attrName, value)); 524 } 525 } 526 527 private void addAttribute(List<RawAttribute> attributes, String attrName, List<String> attrValues) 528 { 529 if (attrValues != null && !attrValues.isEmpty()) 530 { 531 attributes.add(new LDAPAttribute(attrName, attrValues)); 532 } 533 } 534 535 @Override 536 public String getTaskObjectclass() { 537 return "ds-task-import"; 538 } 539 540 @Override 541 public Class<?> getTaskClass() { 542 return ImportTask.class; 543 } 544 545 @Override 546 protected int processLocal(boolean initializeServer, 547 PrintStream out, 548 PrintStream err) { 549 550 551 // Perform the initial bootstrap of the Directory Server and process the configuration. 552 DirectoryServer directoryServer = DirectoryServer.getInstance(); 553 if (initializeServer) 554 { 555 try 556 { 557 DirectoryServer.bootstrapClient(); 558 DirectoryServer.initializeJMX(); 559 } 560 catch (Exception e) 561 { 562 printWrappedText(err, ERR_SERVER_BOOTSTRAP_ERROR.get(getExceptionMessage(e))); 563 return 1; 564 } 565 566 try 567 { 568 directoryServer.initializeConfiguration(configClass.getValue(), 569 configFile.getValue()); 570 } 571 catch (InitializationException ie) 572 { 573 printWrappedText(err, ERR_CANNOT_LOAD_CONFIG.get(ie.getMessage())); 574 return 1; 575 } 576 catch (Exception e) 577 { 578 printWrappedText(err, ERR_CANNOT_LOAD_CONFIG.get(getExceptionMessage(e))); 579 return 1; 580 } 581 582 583 584 // Initialize the Directory Server schema elements. 585 try 586 { 587 directoryServer.initializeSchema(); 588 } 589 catch (Exception e) 590 { 591 printWrappedText(err, ERR_CANNOT_LOAD_SCHEMA.get(getMessage(e))); 592 return 1; 593 } 594 595 596 // Initialize the Directory Server core configuration. 597 try 598 { 599 CoreConfigManager coreConfigManager = new CoreConfigManager(directoryServer.getServerContext()); 600 coreConfigManager.initializeCoreConfig(); 601 } 602 catch (Exception e) 603 { 604 printWrappedText(err, ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(getMessage(e))); 605 return 1; 606 } 607 608 609 // Initialize the Directory Server crypto manager. 610 try 611 { 612 directoryServer.initializeCryptoManager(); 613 } 614 catch (Exception e) 615 { 616 printWrappedText(err, ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(getMessage(e))); 617 return 1; 618 } 619 620 621 if (! quietMode.isPresent()) 622 { 623 try 624 { 625 ErrorLogPublisher errorLogPublisher = 626 TextErrorLogPublisher.getToolStartupTextErrorPublisher( 627 new TextWriter.STREAM(out)); 628 ErrorLogger.getInstance().addLogPublisher(errorLogPublisher); 629 } 630 catch(Exception e) 631 { 632 err.println("Error installing the custom error logger: " + 633 stackTraceToSingleLineString(e)); 634 } 635 } 636 637 // Initialize the root DNs. 638 try 639 { 640 directoryServer.initializeRootDNConfigManager(); 641 } 642 catch (Exception e) 643 { 644 printWrappedText(err, ERR_CANNOT_INITIALIZE_ROOTDN_MANAGER.get(getMessage(e))); 645 return 1; 646 } 647 648 // Initialize the plugin manager. 649 try 650 { 651 HashSet<PluginType> pluginTypes = new HashSet<>(1); 652 directoryServer.initializePlugins(pluginTypes); 653 } 654 catch (Exception e) 655 { 656 printWrappedText(err, ERR_LDIFIMPORT_CANNOT_INITIALIZE_PLUGINS.get(getMessage(e))); 657 return 1; 658 } 659 660 // Initialize the subentry manager. 661 try 662 { 663 directoryServer.initializeSubentryManager(); 664 } 665 catch (InitializationException ie) 666 { 667 printWrappedText(err, ERR_CANNOT_INITIALIZE_SUBENTRY_MANAGER.get(ie.getMessage())); 668 return 1; 669 } 670 671 // Initialize all the password policy information. 672 try 673 { 674 directoryServer.initializeAuthenticationPolicyComponents(); 675 } 676 catch (Exception e) 677 { 678 printWrappedText(err, ERR_LDIFIMPORT_CANNOT_INITIALIZE_PWPOLICY.get(getMessage(e))); 679 return 1; 680 } 681 } 682 683 // Make sure that the plugin initialization is performed. 684 try 685 { 686 HashSet<PluginType> pluginTypes = new HashSet<>(1); 687 pluginTypes.add(PluginType.LDIF_IMPORT); 688 PluginConfigManager pluginConfigManager = 689 DirectoryServer.getPluginConfigManager(); 690 pluginConfigManager.initializeUserPlugins(pluginTypes); 691 } 692 catch (Exception e) 693 { 694 printWrappedText(err, ERR_LDIFIMPORT_CANNOT_INITIALIZE_PLUGINS.get(getMessage(e))); 695 return 1; 696 } 697 698 // See if there were any user-defined sets of include/exclude attributes or 699 // filters. If so, then process them. 700 HashSet<AttributeType> excludeAttributes; 701 boolean excludeAllUserAttributes = false; 702 boolean excludeAllOperationalAttributes = false; 703 if (excludeAttributeStrings == null) 704 { 705 excludeAttributes = null; 706 } 707 else 708 { 709 excludeAttributes = new HashSet<>(); 710 for (String attrName : excludeAttributeStrings.getValues()) 711 { 712 String lowerName = attrName.toLowerCase(); 713 if (lowerName.equals("*")) 714 { 715 excludeAllUserAttributes = true; 716 } 717 else if (lowerName.equals("+")) 718 { 719 excludeAllOperationalAttributes = true; 720 } 721 else 722 { 723 excludeAttributes.add(DirectoryServer.getAttributeTypeOrDefault(lowerName, attrName)); 724 } 725 } 726 } 727 728 HashSet<AttributeType> includeAttributes; 729 boolean includeAllUserAttributes = false; 730 boolean includeAllOperationalAttributes = false; 731 if (includeAttributeStrings == null) 732 { 733 includeAttributes = null; 734 } 735 else 736 { 737 includeAttributes = new HashSet<>(); 738 for (String attrName : includeAttributeStrings.getValues()) 739 { 740 String lowerName = attrName.toLowerCase(); 741 if (lowerName.equals("*")) 742 { 743 includeAllUserAttributes = true; 744 } 745 else if (lowerName.equals("+")) 746 { 747 includeAllOperationalAttributes = true; 748 } 749 else 750 { 751 includeAttributes.add(DirectoryServer.getAttributeTypeOrDefault(lowerName, attrName)); 752 } 753 } 754 } 755 756 ArrayList<SearchFilter> excludeFilters; 757 if (excludeFilterStrings == null) 758 { 759 excludeFilters = null; 760 } 761 else 762 { 763 excludeFilters = new ArrayList<>(); 764 for (String filterString : excludeFilterStrings.getValues()) 765 { 766 try 767 { 768 excludeFilters.add(SearchFilter.createFilterFromString(filterString)); 769 } 770 catch (DirectoryException de) 771 { 772 logger.error(ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER, filterString, de.getMessageObject()); 773 return 1; 774 } 775 catch (Exception e) 776 { 777 logger.error(ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER, filterString, getExceptionMessage(e)); 778 return 1; 779 } 780 } 781 } 782 783 ArrayList<SearchFilter> includeFilters; 784 if (includeFilterStrings == null) 785 { 786 includeFilters = null; 787 } 788 else 789 { 790 includeFilters = new ArrayList<>(); 791 for (String filterString : includeFilterStrings.getValues()) 792 { 793 try 794 { 795 includeFilters.add(SearchFilter.createFilterFromString(filterString)); 796 } 797 catch (DirectoryException de) 798 { 799 logger.error(ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER, filterString, de.getMessageObject()); 800 return 1; 801 } 802 catch (Exception e) 803 { 804 logger.error(ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER, filterString, getExceptionMessage(e)); 805 return 1; 806 } 807 } 808 } 809 810 811 // Get information about the backends defined in the server. Iterate 812 // through them, finding the one backend into which the LDIF should be 813 // imported and finding backends with subordinate base DNs that should be 814 // excluded from the import. 815 Backend<?> backend = null; 816 Set<DN> defaultIncludeBranches = null; 817 Set<DN> excludeBranches = new HashSet<>(); 818 Set<DN> includeBranches = new HashSet<>(); 819 820 if (includeBranchStrings.isPresent()) 821 { 822 for (String s : includeBranchStrings.getValues()) 823 { 824 DN includeBranch; 825 try 826 { 827 includeBranch = DN.valueOf(s); 828 } 829 catch (DirectoryException de) 830 { 831 logger.error(ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE, s, de.getMessageObject()); 832 return 1; 833 } 834 catch (Exception e) 835 { 836 logger.error(ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE, s, getExceptionMessage(e)); 837 return 1; 838 } 839 840 includeBranches.add(includeBranch); 841 } 842 } 843 844 ArrayList<Backend> backendList = new ArrayList<>(); 845 ArrayList<BackendCfg> entryList = new ArrayList<>(); 846 ArrayList<List<DN>> dnList = new ArrayList<>(); 847 int code = BackendToolUtils.getBackends(backendList, entryList, dnList); 848 if (code != 0) 849 { 850 return code; 851 } 852 853 int numBackends = backendList.size(); 854 for (int i=0; i < numBackends; i++) 855 { 856 Backend<?> b = backendList.get(i); 857 858 if(backendID.isPresent()) 859 { 860 if (! backendID.getValue().equals(b.getBackendID())) 861 { 862 continue; 863 } 864 } 865 else 866 { 867 if (!useBackend(includeBranches, dnList.get(i))) 868 { 869 continue; 870 } 871 } 872 873 if (backend == null) 874 { 875 backend = b; 876 defaultIncludeBranches = new HashSet<>(dnList.get(i)); 877 } 878 else 879 { 880 logger.error(ERR_LDIFIMPORT_MULTIPLE_BACKENDS_FOR_ID); 881 return 1; 882 } 883 } 884 885 if (backend == null) 886 { 887 logger.error(ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID); 888 return 1; 889 } 890 else if (!backend.supports(BackendOperation.LDIF_IMPORT)) 891 { 892 logger.error(ERR_LDIFIMPORT_CANNOT_IMPORT, backendID.getValue()); 893 return 1; 894 } 895 896 for (List<DN> baseList : dnList) 897 { 898 for (DN baseDN : baseList) 899 { 900 for (DN importBase : defaultIncludeBranches) 901 { 902 if (!baseDN.equals(importBase) && baseDN.isDescendantOf(importBase)) 903 { 904 excludeBranches.add(baseDN); 905 break; 906 } 907 } 908 } 909 } 910 911 for (String s : excludeBranchStrings.getValues()) 912 { 913 DN excludeBranch; 914 try 915 { 916 excludeBranch = DN.valueOf(s); 917 } 918 catch (DirectoryException de) 919 { 920 logger.error(ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE, s, de.getMessageObject()); 921 return 1; 922 } 923 catch (Exception e) 924 { 925 logger.error(ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE, s, getExceptionMessage(e)); 926 return 1; 927 } 928 929 excludeBranches.add(excludeBranch); 930 } 931 932 if (! includeBranchStrings.isPresent()) 933 { 934 includeBranches = defaultIncludeBranches; 935 } 936 else 937 { 938 // Make sure the selected backend will handle all the include branches 939 for(DN includeBranch : includeBranches) 940 { 941 if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches, 942 excludeBranches)) 943 { 944 logger.error(ERR_LDIFIMPORT_INVALID_INCLUDE_BASE, includeBranch, backendID.getValue()); 945 return 1; 946 } 947 } 948 } 949 950 951 // See if the data should be read from LDIF files or generated via MakeLDIF. 952 LDIFImportConfig importConfig; 953 if (ldifFiles.isPresent()) 954 { 955 ArrayList<String> fileList = new ArrayList<>(ldifFiles.getValues()); 956 int badFileCount = 0; 957 for (String pathname : fileList) 958 { 959 File f = new File(pathname); 960 if (!f.canRead()) 961 { 962 logger.error(ERR_LDIFIMPORT_CANNOT_READ_FILE, pathname); 963 badFileCount++; 964 } 965 } 966 if (badFileCount > 0) 967 { 968 return 1; 969 } 970 importConfig = new LDIFImportConfig(fileList); 971 } 972 else 973 { 974 Random random = newRandom(); 975 976 String resourcePath = DirectoryServer.getInstanceRoot() + File.separator + 977 PATH_MAKELDIF_RESOURCE_DIR; 978 TemplateFile tf = new TemplateFile(resourcePath, random); 979 980 ArrayList<LocalizableMessage> warnings = new ArrayList<>(); 981 try 982 { 983 tf.parse(templateFile.getValue(), warnings); 984 } 985 catch (Exception e) 986 { 987 logger.error(ERR_LDIFIMPORT_CANNOT_PARSE_TEMPLATE_FILE, templateFile.getValue(), e.getMessage()); 988 return 1; 989 } 990 991 importConfig = new LDIFImportConfig(tf); 992 } 993 994 995 // Create the LDIF import configuration to use when reading the LDIF. 996 importConfig.setCompressed(isCompressed.isPresent()); 997 importConfig.setClearBackend(clearBackend.isPresent()); 998 importConfig.setEncrypted(isEncrypted.isPresent()); 999 importConfig.setExcludeAttributes(excludeAttributes); 1000 importConfig.setExcludeBranches(excludeBranches); 1001 importConfig.setExcludeFilters(excludeFilters); 1002 importConfig.setIncludeAttributes(includeAttributes); 1003 importConfig.setIncludeBranches(includeBranches); 1004 importConfig.setIncludeFilters(includeFilters); 1005 importConfig.setValidateSchema(!skipSchemaValidation.isPresent()); 1006 importConfig.setSkipDNValidation(skipDNValidation.isPresent()); 1007 importConfig.setTmpDirectory(tmpDirectory.getValue()); 1008 1009 try 1010 { 1011 importConfig.setThreadCount(threadCount.getIntValue()); 1012 } 1013 catch(Exception e) 1014 { 1015 logger.error(ERR_LDIFIMPORT_CANNOT_PARSE_THREAD_COUNT, 1016 threadCount.getValue(), e.getMessage()); 1017 return 1; 1018 } 1019 1020 importConfig.setBufferSize(LDIF_BUFFER_SIZE); 1021 importConfig.setExcludeAllUserAttributes(excludeAllUserAttributes); 1022 importConfig.setExcludeAllOperationalAttributes(excludeAllOperationalAttributes); 1023 importConfig.setIncludeAllOpAttributes(includeAllOperationalAttributes); 1024 importConfig.setIncludeAllUserAttributes(includeAllUserAttributes); 1025 1026 // FIXME -- Should this be conditional? 1027 importConfig.setInvokeImportPlugins(true); 1028 1029 if (rejectFile != null) 1030 { 1031 try 1032 { 1033 ExistingFileBehavior existingBehavior = overwrite.isPresent() 1034 ? ExistingFileBehavior.OVERWRITE 1035 : ExistingFileBehavior.APPEND; 1036 1037 importConfig.writeRejectedEntries(rejectFile.getValue(), 1038 existingBehavior); 1039 } 1040 catch (Exception e) 1041 { 1042 logger.error(ERR_LDIFIMPORT_CANNOT_OPEN_REJECTS_FILE, rejectFile.getValue(), getExceptionMessage(e)); 1043 return 1; 1044 } 1045 } 1046 1047 if (skipFile != null) 1048 { 1049 try 1050 { 1051 ExistingFileBehavior existingBehavior = overwrite.isPresent() 1052 ? ExistingFileBehavior.OVERWRITE 1053 : ExistingFileBehavior.APPEND; 1054 1055 importConfig.writeSkippedEntries(skipFile.getValue(), 1056 existingBehavior); 1057 } 1058 catch (Exception e) 1059 { 1060 logger.error(ERR_LDIFIMPORT_CANNOT_OPEN_SKIP_FILE, skipFile.getValue(), getExceptionMessage(e)); 1061 return 1; 1062 } 1063 } 1064 1065 // Get the set of base DNs for the backend as an array. 1066 DN[] baseDNs = new DN[defaultIncludeBranches.size()]; 1067 defaultIncludeBranches.toArray(baseDNs); 1068 1069 1070 // Acquire an exclusive lock for the backend. 1071 try 1072 { 1073 String lockFile = LockFileManager.getBackendLockFileName(backend); 1074 StringBuilder failureReason = new StringBuilder(); 1075 if (! LockFileManager.acquireExclusiveLock(lockFile, failureReason)) 1076 { 1077 logger.error(ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND, backend.getBackendID(), failureReason); 1078 return 1; 1079 } 1080 } 1081 catch (Exception e) 1082 { 1083 logger.error(ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND, backend.getBackendID(), getExceptionMessage(e)); 1084 return 1; 1085 } 1086 1087 1088 // Launch the import. 1089 int retCode = 0; 1090 try 1091 { 1092 LDIFImportResult importResult = 1093 backend.importLDIF(importConfig, DirectoryServer.getInstance().getServerContext()); 1094 if (countRejects.isPresent()) 1095 { 1096 if (importResult.getEntriesRejected() > Integer.MAX_VALUE) 1097 { 1098 retCode = Integer.MAX_VALUE; 1099 } 1100 else 1101 { 1102 retCode = (int) importResult.getEntriesRejected(); 1103 } 1104 } 1105 } 1106 catch (DirectoryException de) 1107 { 1108 LocalizableMessage msg; 1109 if (de.getResultCode() == ResultCode.CONSTRAINT_VIOLATION) 1110 { 1111 msg = ERR_LDIFIMPORT_ERROR_CONSTRAINT_VIOLATION.get(); 1112 } 1113 else 1114 { 1115 msg = de.getMessageObject(); 1116 } 1117 logger.error(ERR_LDIFIMPORT_ERROR_DURING_IMPORT.get(msg)); 1118 retCode = 1; 1119 } 1120 catch (Exception e) 1121 { 1122 logger.error(ERR_LDIFIMPORT_ERROR_DURING_IMPORT, getExceptionMessage(e)); 1123 retCode = 1; 1124 } 1125 1126 1127 // Release the exclusive lock on the backend. 1128 try 1129 { 1130 String lockFile = LockFileManager.getBackendLockFileName(backend); 1131 StringBuilder failureReason = new StringBuilder(); 1132 if (! LockFileManager.releaseLock(lockFile, failureReason)) 1133 { 1134 logger.warn(WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND, backend.getBackendID(), failureReason); 1135 retCode = 1; 1136 } 1137 } 1138 catch (Exception e) 1139 { 1140 logger.warn(WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND, backend.getBackendID(), getExceptionMessage(e)); 1141 retCode = 1; 1142 } 1143 1144 1145 // Clean up after the import by closing the import config. 1146 importConfig.close(); 1147 return retCode; 1148 } 1149 1150 private Object getMessage(Exception e) 1151 { 1152 try 1153 { 1154 throw e; 1155 } 1156 catch (ConfigException | InitializationException e2) 1157 { 1158 return e2.getMessage(); 1159 } 1160 catch (Exception e2) 1161 { 1162 return getExceptionMessage(e2); 1163 } 1164 } 1165 1166 private boolean useBackend(Set<DN> includeBranches, List<DN> dnlist) 1167 { 1168 for (DN baseDN : dnlist) 1169 { 1170 for (DN includeDN : includeBranches) 1171 { 1172 if (baseDN.isAncestorOf(includeDN)) 1173 { 1174 return true; 1175 } 1176 } 1177 } 1178 return false; 1179 } 1180 1181 private Random newRandom() 1182 { 1183 if (randomSeed.isPresent()) 1184 { 1185 try 1186 { 1187 return new Random(randomSeed.getIntValue()); 1188 } 1189 catch (Exception ignored) 1190 { 1191 // ignore 1192 } 1193 } 1194 return new Random(); 1195 } 1196 1197 @Override 1198 public String getTaskId() { 1199 // NYI. 1200 return null; 1201 } 1202}