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 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.Utils.*; 034 035import java.io.OutputStream; 036import java.io.PrintStream; 037import java.util.ArrayList; 038import java.util.List; 039import java.util.logging.Level; 040 041import org.forgerock.i18n.LocalizableMessage; 042import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1; 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.backends.RebuildConfig; 049import org.opends.server.backends.RebuildConfig.RebuildMode; 050import org.opends.server.core.CoreConfigManager; 051import org.opends.server.core.DirectoryServer; 052import org.opends.server.core.LockFileManager; 053import org.opends.server.extensions.ConfigFileHandler; 054import org.opends.server.loggers.DebugLogger; 055import org.opends.server.loggers.ErrorLogPublisher; 056import org.opends.server.loggers.ErrorLogger; 057import org.opends.server.loggers.JDKLogging; 058import org.opends.server.loggers.TextErrorLogPublisher; 059import org.opends.server.loggers.TextWriter; 060import org.opends.server.protocols.ldap.LDAPAttribute; 061import org.opends.server.tasks.RebuildTask; 062import org.opends.server.tools.tasks.TaskTool; 063import org.opends.server.types.DN; 064import org.opends.server.types.InitializationException; 065import org.opends.server.types.NullOutputStream; 066import org.opends.server.types.RawAttribute; 067import org.opends.server.util.StaticUtils; 068import org.opends.server.util.args.LDAPConnectionArgumentParser; 069 070import com.forgerock.opendj.cli.ArgumentException; 071import com.forgerock.opendj.cli.BooleanArgument; 072import com.forgerock.opendj.cli.CommonArguments; 073import com.forgerock.opendj.cli.StringArgument; 074 075/** 076 * This program provides a utility to rebuild the contents of the indexes of a 077 * Directory Server backend. This will be a process that is intended to run 078 * separate from Directory Server and not internally within the server process 079 * (e.g., via the tasks interface). 080 */ 081public class RebuildIndex extends TaskTool 082{ 083 084 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 085 086 private StringArgument configClass; 087 private StringArgument configFile; 088 private StringArgument baseDNString; 089 private StringArgument indexList; 090 private StringArgument tmpDirectory; 091 private BooleanArgument rebuildAll; 092 private BooleanArgument rebuildDegraded; 093 private BooleanArgument clearDegradedState; 094 095 private final LDAPConnectionArgumentParser argParser = createArgParser( 096 "org.opends.server.tools.RebuildIndex", 097 INFO_REBUILDINDEX_TOOL_DESCRIPTION.get()); 098 099 private RebuildConfig rebuildConfig = new RebuildConfig(); 100 private Backend<?> currentBackend; 101 102 /** 103 * Processes the command-line arguments and invokes the rebuild process. 104 * 105 * @param args 106 * The command-line arguments provided to this program. 107 */ 108 public static void main(final String[] args) 109 { 110 final int retCode = 111 mainRebuildIndex(args, true, System.out, System.err); 112 if (retCode != 0) 113 { 114 System.exit(filterExitCode(retCode)); 115 } 116 } 117 118 /** 119 * Processes the command-line arguments and invokes the rebuild process. 120 * 121 * @param args 122 * The command-line arguments provided to this program. 123 * @param initializeServer 124 * Indicates whether to initialize the server. 125 * @param outStream 126 * The output stream to use for standard output, or {@code null} if 127 * standard output is not needed. 128 * @param errStream 129 * The output stream to use for standard error, or {@code null} if 130 * standard error is not needed. 131 * @return The error code. 132 */ 133 public static int mainRebuildIndex(final String[] args, 134 final boolean initializeServer, final OutputStream outStream, 135 final OutputStream errStream) 136 { 137 final RebuildIndex tool = new RebuildIndex(); 138 return tool.process(args, initializeServer, outStream, errStream); 139 } 140 141 private int process(final String[] args, final boolean initializeServer, 142 final OutputStream outStream, final OutputStream errStream ) 143 { 144 final PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 145 final PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 146 JDKLogging.enableConsoleLoggingForOpenDJ(Level.FINE); 147 148 // Initialize all the command-line argument types and register them with the 149 // parser. 150 try 151 { 152 initializeArguments(false); 153 } 154 catch (ArgumentException ae) 155 { 156 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 157 return 1; 158 } 159 160 // Parse the command-line arguments provided to this program. 161 try 162 { 163 argParser.parseArguments(args); 164 } 165 catch (ArgumentException ae) 166 { 167 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 168 return 1; 169 } 170 171 // If we should just display usage or version information, 172 // then print it and exit. 173 if (argParser.usageOrVersionDisplayed()) 174 { 175 return 0; 176 } 177 178 if (indexList.getValues().isEmpty() 179 && !rebuildAll.isPresent() 180 && !rebuildDegraded.isPresent()) 181 { 182 argParser.displayMessageAndUsageReference(err, ERR_REBUILDINDEX_REQUIRES_AT_LEAST_ONE_INDEX.get()); 183 return 1; 184 } 185 186 if (rebuildAll.isPresent() && indexList.isPresent()) 187 { 188 argParser.displayMessageAndUsageReference(err, ERR_REBUILDINDEX_REBUILD_ALL_ERROR.get()); 189 return 1; 190 } 191 192 if (rebuildDegraded.isPresent() && indexList.isPresent()) 193 { 194 argParser.displayMessageAndUsageReference(err, ERR_REBUILDINDEX_REBUILD_DEGRADED_ERROR.get("index")); 195 return 1; 196 } 197 198 if (rebuildDegraded.isPresent() && clearDegradedState.isPresent()) 199 { 200 argParser.displayMessageAndUsageReference(err, ERR_REBUILDINDEX_REBUILD_DEGRADED_ERROR.get("clearDegradedState")); 201 return 1; 202 } 203 204 if (rebuildAll.isPresent() && rebuildDegraded.isPresent()) 205 { 206 argParser.displayMessageAndUsageReference(err, 207 ERR_REBUILDINDEX_REBUILD_ALL_DEGRADED_ERROR.get("rebuildDegraded")); 208 return 1; 209 } 210 211 if (rebuildAll.isPresent() && clearDegradedState.isPresent()) 212 { 213 argParser.displayMessageAndUsageReference(err, 214 ERR_REBUILDINDEX_REBUILD_ALL_DEGRADED_ERROR.get("clearDegradedState")); 215 return 1; 216 } 217 218 // Checks the version - if upgrade required, the tool is unusable 219 try 220 { 221 checkVersion(); 222 } 223 catch (InitializationException e) 224 { 225 printWrappedText(err, e.getMessage()); 226 return 1; 227 } 228 return process(argParser, initializeServer, out, err); 229 } 230 231 /** 232 * Initializes the arguments for the rebuild index tool. 233 * 234 * @param isMultipleBackends 235 * {@code true} if the tool is used as internal. 236 * @throws ArgumentException 237 * If the initialization fails. 238 */ 239 private void initializeArguments(final boolean isMultipleBackends) 240 throws ArgumentException 241 { 242 argParser.setShortToolDescription(REF_SHORT_DESC_REBUILD_INDEX.get()); 243 244 configClass = 245 new StringArgument("configclass", 'C', "configClass", true, false, 246 true, INFO_CONFIGCLASS_PLACEHOLDER.get(), ConfigFileHandler.class 247 .getName(), null, INFO_DESCRIPTION_CONFIG_CLASS.get()); 248 configClass.setHidden(true); 249 argParser.addArgument(configClass); 250 251 configFile = 252 new StringArgument("configfile", 'f', "configFile", true, false, true, 253 INFO_CONFIGFILE_PLACEHOLDER.get(), null, null, 254 INFO_DESCRIPTION_CONFIG_FILE.get()); 255 configFile.setHidden(true); 256 argParser.addArgument(configFile); 257 258 259 baseDNString = 260 new StringArgument("basedn", 'b', "baseDN", true, isMultipleBackends, 261 true, INFO_BASEDN_PLACEHOLDER.get(), null, null, 262 INFO_REBUILDINDEX_DESCRIPTION_BASE_DN.get()); 263 argParser.addArgument(baseDNString); 264 265 266 indexList = 267 new StringArgument("index", 'i', "index", false, true, true, 268 INFO_INDEX_PLACEHOLDER.get(), null, null, 269 INFO_REBUILDINDEX_DESCRIPTION_INDEX_NAME.get()); 270 argParser.addArgument(indexList); 271 272 rebuildAll = 273 new BooleanArgument("rebuildAll", null, "rebuildAll", 274 INFO_REBUILDINDEX_DESCRIPTION_REBUILD_ALL.get()); 275 argParser.addArgument(rebuildAll); 276 277 rebuildDegraded = 278 new BooleanArgument("rebuildDegraded", null, "rebuildDegraded", 279 INFO_REBUILDINDEX_DESCRIPTION_REBUILD_DEGRADED.get()); 280 argParser.addArgument(rebuildDegraded); 281 282 clearDegradedState = 283 new BooleanArgument("clearDegradedState", null, "clearDegradedState", 284 INFO_REBUILDINDEX_DESCRIPTION_CLEAR_DEGRADED_STATE.get()); 285 argParser.addArgument(clearDegradedState); 286 287 tmpDirectory = 288 new StringArgument("tmpdirectory", null, "tmpdirectory", false, false, 289 true, INFO_REBUILDINDEX_TEMP_DIR_PLACEHOLDER.get(), "import-tmp", 290 null, INFO_REBUILDINDEX_DESCRIPTION_TEMP_DIRECTORY.get()); 291 argParser.addArgument(tmpDirectory); 292 293 final BooleanArgument displayUsage = CommonArguments.getShowUsage(); 294 argParser.addArgument(displayUsage); 295 argParser.setUsageArgument(displayUsage); 296 } 297 298 /** {@inheritDoc} */ 299 @Override 300 protected int processLocal(final boolean initializeServer, 301 final PrintStream out, final PrintStream err) 302 { 303 // Performs the initial bootstrap of the Directory Server and processes the 304 // configuration. 305 final DirectoryServer directoryServer = DirectoryServer.getInstance(); 306 if (initializeServer) 307 { 308 final int init = initializeServer(directoryServer, out, err); 309 if (init != 0) 310 { 311 return init; 312 } 313 setErrorAndDebugLogPublisher(out, err); 314 } 315 316 if (!configureRebuildProcess(baseDNString.getValue())) 317 { 318 return 1; 319 } 320 321 return rebuildIndex(currentBackend, rebuildConfig); 322 } 323 324 /** 325 * Configures the rebuild index process. i.e.: decodes the selected DN and 326 * retrieves the backend which holds it. Finally, initializes and sets the 327 * rebuild configuration. 328 * 329 * @param dn 330 * User selected base DN. 331 * @return A boolean representing the result of the process. 332 */ 333 private boolean configureRebuildProcess(final String dn) { 334 // Decodes the base DN provided by the user. 335 DN rebuildBaseDN = null; 336 try 337 { 338 rebuildBaseDN = DN.valueOf(dn); 339 } 340 catch (Exception e) 341 { 342 logger.error(ERR_CANNOT_DECODE_BASE_DN, dn, 343 getExceptionMessage(e)); 344 return false; 345 } 346 347 // Retrieves the backend which holds the selected base DN. 348 try 349 { 350 setCurrentBackend(retrieveBackend(rebuildBaseDN)); 351 } 352 catch (Exception e) 353 { 354 logger.error(LocalizableMessage.raw(e.getMessage())); 355 return false; 356 } 357 358 setRebuildConfig(initializeRebuildIndexConfiguration(rebuildBaseDN)); 359 return true; 360 } 361 362 /** 363 * Defines the error and the debug log publisher used in this tool. 364 * 365 * @param out 366 * The output stream to use for standard output, or {@code null} if 367 * standard output is not needed. 368 * @param err 369 * The output stream to use for standard error, or {@code null} if 370 * standard error is not needed. 371 */ 372 private void setErrorAndDebugLogPublisher(final PrintStream out, 373 final PrintStream err) 374 { 375 try 376 { 377 final ErrorLogPublisher errorLogPublisher = 378 TextErrorLogPublisher 379 .getToolStartupTextErrorPublisher(new TextWriter.STREAM(out)); 380 ErrorLogger.getInstance().addLogPublisher(errorLogPublisher); 381 DebugLogger.getInstance().addPublisherIfRequired(new TextWriter.STREAM(out)); 382 } 383 catch (Exception e) 384 { 385 err.println("Error installing the custom error logger: " 386 + stackTraceToSingleLineString(e)); 387 } 388 } 389 390 /** 391 * Initializes the directory server.<br /> 392 * Processes to : 393 * - bootstrapClient 394 * - initializeJMX 395 * - initializeConfiguration 396 * - initializeSchema 397 * - coreConfigManager.initializeCoreConfig() 398 * - initializeCryptoManager 399 * 400 * @param directoryServer 401 * The current instance. 402 * @param out 403 * The output stream to use for standard output, or {@code null} if 404 * standard output is not needed. 405 * @param err 406 * The output stream to use for standard error, or {@code null} if 407 * standard error is not needed. 408 * @return The result code. 409 */ 410 private int initializeServer(final DirectoryServer directoryServer, 411 final PrintStream out, final PrintStream err) 412 { 413 try 414 { 415 DirectoryServer.bootstrapClient(); 416 DirectoryServer.initializeJMX(); 417 } 418 catch (Exception e) 419 { 420 printWrappedText(err, ERR_SERVER_BOOTSTRAP_ERROR.get(getExceptionMessage(e))); 421 return 1; 422 } 423 424 try 425 { 426 directoryServer.initializeConfiguration(configClass.getValue(), 427 configFile.getValue()); 428 } 429 catch (Exception ex) 430 { 431 printWrappedText(err, toErrorMsg(ERR_CANNOT_LOAD_CONFIG, ex)); 432 return 1; 433 } 434 435 // Initializes the Directory Server schema elements. 436 try 437 { 438 directoryServer.initializeSchema(); 439 } 440 catch (Exception e) 441 { 442 printWrappedText(err, toErrorMsg(ERR_CANNOT_LOAD_SCHEMA, e)); 443 return 1; 444 } 445 446 // Initializes the Directory Server core configuration. 447 try 448 { 449 final CoreConfigManager coreConfigManager = new CoreConfigManager(directoryServer.getServerContext()); 450 coreConfigManager.initializeCoreConfig(); 451 } 452 catch (Exception ex) 453 { 454 printWrappedText(err, toErrorMsg(ERR_CANNOT_INITIALIZE_CORE_CONFIG, ex)); 455 return 1; 456 } 457 458 // Initializes the Directory Server crypto manager. 459 try 460 { 461 directoryServer.initializeCryptoManager(); 462 } 463 catch (Exception ex) 464 { 465 printWrappedText(err, toErrorMsg(ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER, ex)); 466 return 1; 467 } 468 469 return 0; 470 } 471 472 private String toErrorMsg(Arg1<Object> errorMsg, Exception ex) 473 { 474 final LocalizableMessage message = getErrorMsg(ex, errorMsg); 475 return wrapText(message, MAX_LINE_WIDTH); 476 } 477 478 private LocalizableMessage getErrorMsg(Exception ex, Arg1<Object> errorMsg) 479 { 480 if (ex instanceof ConfigException || ex instanceof InitializationException) 481 { 482 return errorMsg.get(ex.getMessage()); 483 } 484 return errorMsg.get(getExceptionMessage(ex)); 485 } 486 487 /** 488 * Initializes and sets the rebuild index configuration. 489 * 490 * @param rebuildBaseDN 491 * The selected base DN. 492 * @return A rebuild configuration. 493 */ 494 private RebuildConfig initializeRebuildIndexConfiguration( 495 final DN rebuildBaseDN) 496 { 497 final RebuildConfig config = new RebuildConfig(); 498 config.setBaseDN(rebuildBaseDN); 499 for (final String s : indexList.getValues()) 500 { 501 config.addRebuildIndex(s); 502 } 503 504 if (rebuildAll.isPresent()) 505 { 506 config.setRebuildMode(RebuildMode.ALL); 507 } 508 else if (rebuildDegraded.isPresent()) 509 { 510 config.setRebuildMode(RebuildMode.DEGRADED); 511 } 512 else 513 { 514 if (clearDegradedState.isPresent()) 515 { 516 config.isClearDegradedState(true); 517 } 518 config.setRebuildMode(RebuildMode.USER_DEFINED); 519 } 520 521 config.setTmpDirectory(tmpDirectory.getValue()); 522 return config; 523 } 524 525 /** 526 * Launches the rebuild index process. 527 * 528 * @param backend 529 * The directory server backend. 530 * @param rebuildConfig 531 * The configuration which is going to be used by the rebuild index 532 * process. 533 * @return An integer representing the result of the process. 534 */ 535 private int rebuildIndex(final Backend<?> backend, final RebuildConfig rebuildConfig) 536 { 537 // Acquire an exclusive lock for the backend. 538 //TODO: Find a way to do this with the server online. 539 try 540 { 541 final String lockFile = LockFileManager.getBackendLockFileName(backend); 542 final StringBuilder failureReason = new StringBuilder(); 543 if (!LockFileManager.acquireExclusiveLock(lockFile, failureReason)) 544 { 545 logger.error(ERR_REBUILDINDEX_CANNOT_EXCLUSIVE_LOCK_BACKEND, backend.getBackendID(), failureReason); 546 return 1; 547 } 548 } 549 catch (Exception e) 550 { 551 logger.error(ERR_REBUILDINDEX_CANNOT_EXCLUSIVE_LOCK_BACKEND, backend 552 .getBackendID(), getExceptionMessage(e)); 553 return 1; 554 } 555 556 int returnCode = 0; 557 try 558 { 559 backend.rebuildBackend(rebuildConfig, DirectoryServer.getInstance().getServerContext()); 560 } 561 catch (InitializationException e) 562 { 563 logger.error(ERR_REBUILDINDEX_ERROR_DURING_REBUILD, e.getMessage()); 564 returnCode = 1; 565 } 566 catch (Exception e) 567 { 568 logger.error(ERR_REBUILDINDEX_ERROR_DURING_REBUILD, getExceptionMessage(e)); 569 returnCode = 1; 570 } 571 finally 572 { 573 // Release the shared lock on the backend. 574 try 575 { 576 final String lockFile = LockFileManager.getBackendLockFileName(backend); 577 final StringBuilder failureReason = new StringBuilder(); 578 if (!LockFileManager.releaseLock(lockFile, failureReason)) 579 { 580 logger.warn(WARN_REBUILDINDEX_CANNOT_UNLOCK_BACKEND, backend.getBackendID(), failureReason); 581 } 582 } 583 catch (Exception e) 584 { 585 logger.error(WARN_REBUILDINDEX_CANNOT_UNLOCK_BACKEND, backend.getBackendID(), getExceptionMessage(e)); 586 } 587 } 588 589 return returnCode; 590 } 591 592 /** 593 * Gets information about the backends defined in the server. Iterates through 594 * them, finding the one that holds the base DN. 595 * 596 * @param selectedDN 597 * The user selected DN. 598 * @return The backend which holds the selected base DN. 599 * @throws ConfigException 600 * If the backend is poorly configured. 601 * @throws Exception 602 * If an exception occurred during the backend search. 603 */ 604 private Backend<?> retrieveBackend(final DN selectedDN) throws ConfigException, Exception 605 { 606 final ArrayList<Backend> backendList = new ArrayList<>(); 607 final ArrayList<BackendCfg> entryList = new ArrayList<>(); 608 final ArrayList<List<DN>> dnList = new ArrayList<>(); 609 BackendToolUtils.getBackends(backendList, entryList, dnList); 610 611 Backend<?> backend = null; 612 final int numBackends = backendList.size(); 613 for (int i = 0; i < numBackends; i++) 614 { 615 final Backend<?> b = backendList.get(i); 616 final List<DN> baseDNs = dnList.get(i); 617 if (baseDNs.contains(selectedDN)) 618 { 619 if (backend != null) 620 { 621 throw new ConfigException(ERR_MULTIPLE_BACKENDS_FOR_BASE.get(baseDNString.getValue())); 622 } 623 backend = b; 624 } 625 } 626 627 if (backend == null) 628 { 629 throw new ConfigException(ERR_NO_BACKENDS_FOR_BASE.get(baseDNString.getValue())); 630 } 631 if (!backend.supports(BackendOperation.INDEXING)) 632 { 633 throw new ConfigException(ERR_BACKEND_NO_INDEXING_SUPPORT.get()); 634 } 635 return backend; 636 } 637 638 /** 639 * This function allow internal use of the rebuild index tools. This function 640 * rebuilds indexes shared by multiple backends. 641 * 642 * @param initializeServer 643 * Indicates whether to initialize the server. 644 * @param out 645 * The print stream which is used to display errors/debug lines. 646 * Usually redirected into a logger if the tool is used as external. 647 * @param args 648 * The arguments used to launch the rebuild index process. 649 * @return An integer indicating the result of this action. 650 */ 651 public int rebuildIndexesWithinMultipleBackends( 652 final boolean initializeServer, final PrintStream out, 653 final String... args) 654 { 655 try 656 { 657 setErrorAndDebugLogPublisher(out, out); 658 659 try 660 { 661 initializeArguments(true); 662 } 663 catch (ArgumentException ae) 664 { 665 printWrappedText(out, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 666 return 1; 667 } 668 669 try 670 { 671 argParser.parseArguments(args); 672 } 673 catch (ArgumentException ae) 674 { 675 argParser.displayMessageAndUsageReference(out, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 676 return 1; 677 } 678 679 final DirectoryServer directoryServer = DirectoryServer.getInstance(); 680 if (initializeServer) 681 { 682 final int init = initializeServer(directoryServer, out, out); 683 if (init != 0) 684 { 685 return init; 686 } 687 } 688 689 for (final String dn : baseDNString.getValues()) 690 { 691 if (!configureRebuildProcess(dn)) 692 { 693 return 1; 694 } 695 696 final int result = 697 rebuildIndex(getCurrentBackend(), getRebuildConfig()); 698 // If the rebuild index is going bad, process is stopped. 699 if (result != 0) 700 { 701 out.println(String.format( 702 "An error occurs during the rebuild index process" + 703 " in %s, rebuild index(es) aborted.", 704 dn)); 705 return 1; 706 } 707 } 708 } 709 finally 710 { 711 StaticUtils.close(out); 712 } 713 return 0; 714 } 715 716 /** {@inheritDoc} */ 717 @Override 718 public String getTaskId() 719 { 720 // NYI. 721 return null; 722 } 723 724 /** {@inheritDoc} */ 725 @Override 726 public void addTaskAttributes(List<RawAttribute> attributes) 727 { 728 // Required attributes 729 addLdapAttribute(attributes, ATTR_REBUILD_BASE_DN, baseDNString.getValue()); 730 731 attributes.add(new LDAPAttribute(ATTR_REBUILD_INDEX, indexList.getValues())); 732 733 if (hasNonDefaultValue(tmpDirectory)) 734 { 735 addLdapAttribute(attributes, ATTR_REBUILD_TMP_DIRECTORY, tmpDirectory.getValue()); 736 } 737 738 if (hasNonDefaultValue(rebuildAll)) 739 { 740 addLdapAttribute(attributes, ATTR_REBUILD_INDEX, REBUILD_ALL); 741 } 742 743 if (hasNonDefaultValue(rebuildDegraded)) 744 { 745 addLdapAttribute(attributes, ATTR_REBUILD_INDEX, REBUILD_DEGRADED); 746 } 747 748 if (hasNonDefaultValue(clearDegradedState)) 749 { 750 addLdapAttribute(attributes, ATTR_REBUILD_INDEX_CLEARDEGRADEDSTATE, "true"); 751 } 752 } 753 754 private void addLdapAttribute(List<RawAttribute> attributes, String attrType, String attrValue) 755 { 756 attributes.add(new LDAPAttribute(attrType, attrValue)); 757 } 758 759 private boolean hasNonDefaultValue(BooleanArgument arg) 760 { 761 return arg.getValue() != null 762 && !arg.getValue().equals(arg.getDefaultValue()); 763 } 764 765 private boolean hasNonDefaultValue(StringArgument arg) 766 { 767 return arg.getValue() != null 768 && !arg.getValue().equals(arg.getDefaultValue()); 769 } 770 771 /** {@inheritDoc} */ 772 @Override 773 public String getTaskObjectclass() 774 { 775 return "ds-task-rebuild"; 776 } 777 778 /** {@inheritDoc} */ 779 @Override 780 public Class<?> getTaskClass() 781 { 782 return RebuildTask.class; 783 } 784 785 /** 786 * Returns the rebuild configuration. 787 * 788 * @return The rebuild configuration. 789 */ 790 public RebuildConfig getRebuildConfig() 791 { 792 return rebuildConfig; 793 } 794 795 /** 796 * Sets the rebuild configuration. 797 * 798 * @param rebuildConfig 799 * The rebuild configuration to set. 800 */ 801 public void setRebuildConfig(RebuildConfig rebuildConfig) 802 { 803 this.rebuildConfig = rebuildConfig; 804 } 805 806 /** 807 * Returns the current backend. 808 * 809 * @return The current backend. 810 */ 811 public Backend<?> getCurrentBackend() 812 { 813 return currentBackend; 814 } 815 816 /** 817 * Sets the current backend. 818 * 819 * @param currentBackend 820 * The current backend to set. 821 */ 822 public void setCurrentBackend(Backend<?> currentBackend) 823 { 824 this.currentBackend = currentBackend; 825 } 826}